//+---------------------------------------------------------------------------- // // File: connect.cpp // // Module: CMDIAL32.DLL // // Synopsis: The main code path for establishing a connection. // // Copyright (c) 1998-1999 Microsoft Corporation // // Author: nickball Created 2/10/98 // //+---------------------------------------------------------------------------- #include "cmmaster.h" // // Local includes // #include "ConnStat.h" #include "CompChck.h" #include "Dialogs.h" #include "ActList.h" #include "dial_str.h" #include "dun_str.h" #include "dl_str.h" #include "pwd_str.h" #include "tunl_str.h" #include "mon_str.h" #include "conact_str.h" #include "pbk_str.h" #include "stp_str.h" #include "profile_str.h" #include "ras_str.h" #include "cmtiming.h" // // .CMP and .CMS flag used only by connect.cpp // const TCHAR* const c_pszCmEntryMonitorCallingProgram= TEXT("MonitorCallingProgram"); const TCHAR* const c_pszCmEntryUserNameOptional = TEXT("UserNameOptional"); const TCHAR* const c_pszCmEntryDomainOptional = TEXT("DomainOptional"); const TCHAR* const c_pszCmEntryServiceType = TEXT("ServiceType"); const TCHAR* const c_pszCmEntryRedialDelay = TEXT("RedialDelay"); const TCHAR* const c_pszCmEntryRedial = TEXT("Redial"); const TCHAR* const c_pszCmEntryIdle = TEXT("Idle"); const TCHAR* const c_pszCmEntryDialAutoMessage = TEXT("DialAutoMessage"); const TCHAR* const c_pszCmEntryCheckOsComponents = TEXT("CheckOSComponents"); const TCHAR* const c_pszCmEntryDoNotCheckBindings = TEXT("DoNotCheckBindings"); const TCHAR* const c_pszCmEntryIsdnDialMode = TEXT("IsdnDialMode"); const TCHAR* const c_pszCmEntryResetPassword = TEXT("ResetPassword"); const TCHAR* const c_pszCmEntryCustomButtonText = TEXT("CustomButtonText"); const TCHAR* const c_pszCmEntryCustomButtonToolTip = TEXT("CustomButtonToolTip"); const TCHAR* const c_pszCmDynamicPhoneNumber = TEXT("DynamicPhoneNumber"); const TCHAR* const c_pszCmNoDialingRules = TEXT("NoDialingRules"); const TCHAR* const c_pszCmEntryHideDialAuto = TEXT("HideDialAutomatically"); const TCHAR* const c_pszCmEntryHideRememberPwd = TEXT("HideRememberPassword"); const TCHAR* const c_pszCmEntryHideRememberInetPwd = TEXT("HideRememberInternetPassword"); const TCHAR* const c_pszCmEntryHideInetUserName = TEXT("HideInternetUserName"); const TCHAR* const c_pszCmEntryHideInetPassword = TEXT("HideInternetPassword"); const TCHAR* const c_pszCmEntryHideUnattended = TEXT("HideUnattended"); const TCHAR* const c_pszCmEntryRegion = TEXT("Region"); const TCHAR* const c_pszCmEntryPhonePrefix = TEXT("Phone"); const TCHAR* const c_pszCmEntryPhoneCanonical = TEXT("PhoneCanonical"); const TCHAR* const c_pszCmEntryPhoneDunPrefix = TEXT("DUN"); const TCHAR* const c_pszCmEntryPhoneDescPrefix = TEXT("Description"); const TCHAR* const c_pszCmEntryPhoneCountryPrefix = TEXT("PhoneCountry"); const TCHAR* const c_pszCmEntryPhoneSourcePrefix = TEXT("PhoneSource"); const TCHAR* const c_pszCmEntryUseDialingRules = TEXT("UseDialingRules"); const TCHAR* const c_pszCmEntryAnimatedLogo = TEXT("AnimatedLogo"); const TCHAR* const c_pszCmSectionAnimatedLogo = TEXT("Animated Logo"); const TCHAR* const c_pszCmSectionAnimatedActions = TEXT("Animation Actions"); const TCHAR* const c_pszCmEntryAniMovie = TEXT("Movie"); const TCHAR* const c_pszCmEntryAniPsInteractive = TEXT("Initial"); const TCHAR* const c_pszCmEntryAniPsDialing0 = TEXT("Dialing0"); const TCHAR* const c_pszCmEntryAniPsDialing1 = TEXT("Dialing1"); const TCHAR* const c_pszCmEntryAniPsPausing = TEXT("Pausing"); const TCHAR* const c_pszCmEntryAniPsAuthenticating = TEXT("Authenticating"); const TCHAR* const c_pszCmEntryAniPsOnline = TEXT("Connected"); const TCHAR* const c_pszCmEntryAniPsTunnel = TEXT("Tunneling"); const TCHAR* const c_pszCmEntryAniPsError = TEXT("Error"); const TCHAR* const c_pszCmEntryWriteDialParams = TEXT("WriteRasDialUpParams"); // // Used for loading EAP identity DLL // const TCHAR* const c_pszRasEapRegistryLocation = TEXT("System\\CurrentControlSet\\Services\\Rasman\\PPP\\EAP"); const TCHAR* const c_pszRasEapValueNameIdentity = TEXT("IdentityPath"); const TCHAR* const c_pszInvokeUsernameDialog = TEXT("InvokeUsernameDialog"); // // Definitions // #define MAX_OBJECT_WAIT 30000 // milliseconds to wait for cmmon launch and RNA thread return //============================================================================ static void LoadPhoneInfoFromProfile(ArgsStruct *pArgs); HRESULT UpdateTable(ArgsStruct *pArgs, CmConnectState CmState); HRESULT ConnectMonitor(ArgsStruct *pArgs); void OnMainExit(ArgsStruct *pArgs); void ProcessCleanup(ArgsStruct* pArgs); VOID UpdateError(ArgsStruct *pArgs, DWORD dwErr); DWORD GetEapUserId(ArgsStruct *pArgs, HWND hwndDlg, LPTSTR pszRasPbk, LPBYTE pbEapAuthData, DWORD dwEapAuthDataSize, DWORD dwCustomAuthKey, LPRASEAPUSERIDENTITY* ppRasEapUserIdentity); DWORD CmEapGetIdentity(ArgsStruct *pArgs, LPTSTR pszRasPbk, LPBYTE pbEapAuthData, DWORD dwEapAuthDataSize, LPRASEAPUSERIDENTITY* ppRasEapUserIdentity); void CheckStartupInfo(HWND hwndDlg, ArgsStruct *pArgs); BOOL InitConnect(ArgsStruct *pArgs); void ObfuscatePasswordEdit(ArgsStruct *pArgs); void DeObfuscatePasswordEdit(ArgsStruct *pArgs); void GetPasswordFromEdit(ArgsStruct *pArgs); //+---------------------------------------------------------------------------- // // Function: GetPasswordFromEdit // // Synopsis: Updates pArgs->szPassword with contents of edit control // // Arguments: pArgs - Ptr to global Args struct // // Returns: Nothing // // History: nickball Created 04/13/00 // //+---------------------------------------------------------------------------- void GetPasswordFromEdit(ArgsStruct *pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { return; } if (NULL == GetDlgItem(pArgs->hwndMainDlg, IDC_MAIN_PASSWORD_EDIT)) { return; } // // Retrieve the password and update memory based storage. // LPTSTR pszPassword = CmGetWindowTextAlloc(pArgs->hwndMainDlg, IDC_MAIN_PASSWORD_EDIT); MYDBGASSERT(pszPassword); if (pszPassword) { // // Update pArgs with main password. // lstrcpyU(pArgs->szPassword, pszPassword); CmEncodePassword(pArgs->szPassword); CmWipePassword(pszPassword); CmFree(pszPassword); } else { lstrcpyU(pArgs->szPassword, TEXT("")); } return; } //+---------------------------------------------------------------------------- // // Function: DeObfuscatePasswordEdit // // Synopsis: Undoes the work of ObfuscatePasswordEdit by updating the password // edit with the plain text password // // Arguments: pArgs - Ptr to global Args struct // // Returns: Nothing // // History: nickball Created 04/13/00 // //+---------------------------------------------------------------------------- void DeObfuscatePasswordEdit(ArgsStruct *pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { return; } HWND hwndEdit = GetDlgItem(pArgs->hwndMainDlg, IDC_MAIN_PASSWORD_EDIT); if (NULL == hwndEdit) { return; } // // Make sure we don't trigger EN_CHANGE notifications // BOOL bSavedNoNotify = pArgs->fIgnoreChangeNotification; pArgs->fIgnoreChangeNotification = TRUE; // // Update the edit control // CmDecodePassword(pArgs->szPassword); SetWindowTextU(hwndEdit, pArgs->szPassword); CmEncodePassword(pArgs->szPassword); // // Restore EN_CHANGE notifications // pArgs->fIgnoreChangeNotification = bSavedNoNotify; } //+---------------------------------------------------------------------------- // // Function: ObfuscatePasswordEdit // // Synopsis: Helper routine to mangle password edit contents by replacing // them with an equivalent number of *s // // Arguments: pArgs - Ptr to global Args struct // // Returns: Nothing // // NOTE: This function assumes that pArgs->szPassword has been previously // updated with GetPasswordFromEdit. This assumption is made // because it is critical to the Odfuscate/DeObfuscate sequence, // which will breakdown if the latest password is not cached in // memory (pArgs) before the edit contents are modified. // // History: nickball Created 04/13/00 // //+---------------------------------------------------------------------------- void ObfuscatePasswordEdit(ArgsStruct *pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { return; } HWND hwndEdit = GetDlgItem(pArgs->hwndMainDlg, IDC_MAIN_PASSWORD_EDIT); if (NULL == hwndEdit) { return; } // // Generate a buffer of the same length as the current password, but // containing only asterisks. // LPTSTR pszDummy = CmStrCpyAlloc(pArgs->szPassword); MYDBGASSERT(pszDummy); if (pszDummy) { // // Make sure we don't trigger EN_CHANGE notifications // BOOL bSavedNoNotify = pArgs->fIgnoreChangeNotification; pArgs->fIgnoreChangeNotification = TRUE; LPTSTR pszTmp = pszDummy; while (*pszTmp) { *pszTmp++ = TEXT('*'); } // // Update the edit control with the modified buffer // SetWindowTextU(hwndEdit, pszDummy); CmFree(pszDummy); // // Restore EN_CHANGE notifications // pArgs->fIgnoreChangeNotification = bSavedNoNotify; } } //+---------------------------------------------------------------------------- // // Function: InitConnect // // Synopsis: Init routine for the connection. Assumes that we have the profile // initialized and the basic integrity of the profile verified. // // Arguments: ArgStruct *pArgs - Ptr to global Args struct // // Returns: BOOL - True if init succeeds. // // History: nickball Created 03/10/00 // //+---------------------------------------------------------------------------- BOOL InitConnect(ArgsStruct *pArgs) { // // If this is an AUTODIAL, add the process ID to the watch list // if ((pArgs->dwFlags & FL_AUTODIAL) && pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMonitorCallingProgram, 1)) { CMTRACE(TEXT("InitConnect() Adding calling process to watch list")); AddWatchProcessId(pArgs, GetCurrentProcessId()); } // // Do we want tunneling? // pArgs->fTunnelPrimary = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryTunnelPrimary); pArgs->fTunnelReferences = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryTunnelReferences); // // Now we can determine our connect type // GetConnectType(pArgs); // // Set fUseTunneling. If not obvious (eg. direct VPN) then // base the initial value upon the primary phone number. // if (pArgs->IsDirectConnect()) { pArgs->fUseTunneling = TRUE; } else { pArgs->fUseTunneling = UseTunneling(pArgs, 0); } // // Load the path for the VPN file if we have one // LPTSTR pszTemp = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryTunnelFile); if (pszTemp && pszTemp[0]) { // // Now expand the relative path to a full path // pArgs->pszVpnFile = CmBuildFullPathFromRelative(pArgs->piniProfile->GetFile(), pszTemp); MYDBGASSERT(pArgs->pszVpnFile && pArgs->pszVpnFile[0]); } CmFree(pszTemp); TCHAR szTmp[MAX_PATH]; MYVERIFY(GetModuleFileNameU(NULL, szTmp, MAX_PATH)); pArgs->Log.Log(PREINIT_EVENT, szTmp); // // Run any init time actions that we may have. // CActionList PreInitActList; PreInitActList.Append(pArgs->piniService, c_pszCmSectionPreInit); if (!PreInitActList.RunAccordType(pArgs->hwndMainDlg, pArgs, FALSE)) // fStatusMsgOnFailure = FALSE { // // Fail the connection // return FALSE; } return TRUE; } //+---------------------------------------------------------------------------- // // Function: CheckStartupInfo // // Synopsis: Sub-routine to initialize startup info if necessary and perform // any other functions specific to this juncture in the init sequence. // // Arguments: HWND hwndDlg - HWND of main dlg // ArgStruct *pArgs - Ptr to global Args struct // // Returns: Nothing // // History: nickball Created 10/28/99 // //+---------------------------------------------------------------------------- void CheckStartupInfo(IN HWND hwndDlg, IN ArgsStruct *pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { return; } if (!pArgs->fStartupInfoLoaded) { // // When no one is logged on the IsWindowVisible will not return true when ICS is dialing // if (IsLogonAsSystem() || IsWindowVisible(hwndDlg)) { // // The code is here to make sure FutureSplash starts with // the frame associated with Initial/Interactive state // and not Frame 1 // if (NULL != pArgs->pCtr) { pArgs->pCtr->MapStateToFrame(PS_Interactive); } // // If we're doing unattended, and the behavior isn't explicitly turned off, // hide the UI while we do our unattended dial. Note: Be sure to set hide // state before first paint message is processed by system. // if (pArgs->dwFlags & FL_UNATTENDED) { if (pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideUnattended, TRUE)) { ShowWindow(hwndDlg, SW_HIDE); } } // // Post a message to ourselves to begin loading startup info. // PostMessageU(hwndDlg, WM_LOADSTARTUPINFO, (WPARAM)0, (LPARAM)0); } } } //+---------------------------------------------------------------------------- // // Function: UpdateError // // Synopsis: Simple sub-routine to update the UI and program state in the // event of an error. // // Arguments: ArgStruct *pArgs - Ptr to global Args struct // DWORD dwErr - The error code // // Returns: Nothing // // History: nickball Created 05/31/99 // //+---------------------------------------------------------------------------- VOID UpdateError(ArgsStruct *pArgs, DWORD dwErr) { MYDBGASSERT(pArgs); if (pArgs) { // // Update the status display providing that the special case error code // ERROR_INVALID_DLL is not being used. This code is only used by CM to // designate that a Connect Action failed. Because the display is // updated by the action list, we must ensure that we don't overwrite. // if (ERROR_INVALID_DLL != dwErr) { CheckConnectionError(pArgs->hwndMainDlg, dwErr, pArgs, IsDialingTunnel(pArgs)); } // // Update the logon dialog controls // SetInteractive(pArgs->hwndMainDlg, pArgs); // // Update the program state // pArgs->psState = PS_Error; } } //+---------------------------------------------------------------------------- // // Function: UpdateTable // // Synopsis: Encapsulates updating to Connection Table according to our // current state // // Arguments: ArgsStruct *pArgs - Ptr to global Args struct // CmConnectState CmState - The state we are now in. // // Returns: HRESULT - Failure code. // // History: nickball Created Header 2/9/98 // //+---------------------------------------------------------------------------- HRESULT UpdateTable(ArgsStruct *pArgs, CmConnectState CmState) { MYDBGASSERT(pArgs); MYDBGASSERT(pArgs->pConnTable); HRESULT hrRet = E_FAIL; // // Set the state as appropriate // switch (CmState) { case CM_CONNECTING: hrRet = pArgs->pConnTable->AddEntry(pArgs->szServiceName, pArgs->fAllUser); break; case CM_CONNECTED: hrRet = pArgs->pConnTable->SetConnected(pArgs->szServiceName, pArgs->hrcRasConn, pArgs->hrcTunnelConn); break; case CM_DISCONNECTING: hrRet = pArgs->pConnTable->SetDisconnecting(pArgs->szServiceName); break; case CM_DISCONNECTED: hrRet = pArgs->pConnTable->ClearEntry(pArgs->szServiceName); break; default: MYDBGASSERT(FALSE); break; } return hrRet; } //+---------------------------------------------------------------------------- // // Function: EndMainDialog // // Synopsis: Simple helper to encapsulate EndDialog call and associated clean // up. // // Arguments: HWND hwndDlg - HWND of main dialog // ArgsStruct *pArgs - Ptr to global Args struct // int nResult - int to be passed on the EndDialog // // Returns: Nothing // // History: nickball Created 2/23/98 // //+---------------------------------------------------------------------------- void EndMainDialog(HWND hwndDlg, ArgsStruct *pArgs, int nResult) { // // Kill timer if we have one // if (pArgs->nTimerId) { KillTimer(hwndDlg,pArgs->nTimerId); pArgs->nTimerId = 0; } // // Cleanup future splash // if (pArgs->pCtr) { CleanupCtr(pArgs->pCtr); pArgs->pCtr = NULL; } // // Release our dialog specific data // pArgs->fStartupInfoLoaded = FALSE; OnMainExit(pArgs); // // hasta la vista, final // EndDialog(hwndDlg, nResult); } //+---------------------------------------------------------------------------- // // Function: GetWatchCount // // Synopsis: Determines the number of processes in the watch list by searching // for the first NULL entry. // // Arguments: ArgStruct *pArgs - Ptr to global Args struct // // Returns: DWORD - Number of processes in list // // History: nickball Created Header 2/10/98 // //+---------------------------------------------------------------------------- DWORD GetWatchCount(const ArgsStruct *pArgs) { MYDBGASSERT(pArgs); DWORD dwCnt = 0; if (pArgs && pArgs->phWatchProcesses) { for (DWORD dwIdx = 0; pArgs->phWatchProcesses[dwIdx]; dwIdx++) { dwCnt++; } } return dwCnt; } //+---------------------------------------------------------------------------- // // Function: AddWatchProcess // // Synopsis: Adds the given process handle to our list. The list is allocated // and reallocated as needed to accomodate new entries. // // Arguments: ArgsStruct *pArgs - Ptr to global Args struct // HANDLE hProcess - The process handle to be added to the list // // Returns: Nothing // // History: nickball Created Header 2/10/98 // tomkel Fixed PREFIX issues 11/21/2000 // //+---------------------------------------------------------------------------- void AddWatchProcess(ArgsStruct *pArgs, HANDLE hProcess) { MYDBGASSERT(pArgs); MYDBGASSERT(hProcess); if (NULL == hProcess || NULL == pArgs) { return; } // // Get count and Allocate room for 2 more, 1 new, 1 NULL // DWORD dwCnt = GetWatchCount(pArgs); HANDLE *phTmp = (HANDLE *) CmMalloc((dwCnt+2)*sizeof(HANDLE)); if (NULL != phTmp) { // // Copy the existing list, and add the new handle // if (NULL != pArgs->phWatchProcesses) { CopyMemory(phTmp,pArgs->phWatchProcesses,sizeof(HANDLE)*dwCnt); } phTmp[dwCnt] = hProcess; // // Fix up the pointers // CmFree(pArgs->phWatchProcesses); pArgs->phWatchProcesses = phTmp; } } //+---------------------------------------------------------------------------- // // Function: AddWatchProcessId // // Synopsis: Given a process Id, adds a handle for the given process to the w // atch process list. // // Arguments: ArgsStruct *pArgs - Ptr to global Args struct. // DWORD dwProcessId - The ID of the process to be added // // Returns: Nothing // // History: nickball Created Header 2/10/98 // //+---------------------------------------------------------------------------- void AddWatchProcessId(ArgsStruct *pArgs, DWORD dwProcessId) { MYDBGASSERT(pArgs); MYDBGASSERT(dwProcessId); if (NULL == pArgs || NULL == dwProcessId) { return; } // // Open the process Id to obtain handle // HANDLE hProcess = OpenProcess(SYNCHRONIZE | PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION, FALSE, dwProcessId); // // Add to the watch process list // if (hProcess) { AddWatchProcess(pArgs,hProcess); } else { CMTRACE1(TEXT("AddWatchProcess() OpenProcess() failed, GLE=%u."), GetLastError()); } } //+---------------------------------------------------------------------------- // // Function: CleanupConnect // // Synopsis: Helper function encapsulating release of resource allocated duri // ng connect. // // Arguments: ArgsStruct *pArgs - Ptr to global Args struct // // Returns: Nothing // // History: nickball Created 9/25/98 // //+---------------------------------------------------------------------------- void CleanupConnect(ArgsStruct *pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { return; } pArgs->m_ShellDll.Unload(); // // Unlink RAS and TAPI DLLs // UnlinkFromRas(&pArgs->rlsRasLink); UnlinkFromTapi(&pArgs->tlsTapiLink); // // un-init password encryption, only if it is initialized // if (pArgs->fInitSecureCalled) { DeInitSecure(); pArgs->fInitSecureCalled = FALSE; } // // Cleanup WatchProcess handles // ProcessCleanup(pArgs); // // Release all paths loaded for connect. // if (pArgs->pszRasPbk) { CmFree(pArgs->pszRasPbk); pArgs->pszRasPbk = NULL; } if (pArgs->pszRasHiddenPbk) { CmFree(pArgs->pszRasHiddenPbk); pArgs->pszRasHiddenPbk = NULL; } if(pArgs->pszVpnFile) { CmFree(pArgs->pszVpnFile); pArgs->pszVpnFile = NULL; } if (pArgs->pRasDialExtensions) { CmFree(pArgs->pRasDialExtensions); pArgs->pRasDialExtensions = NULL; } if (pArgs->pRasDialParams) { CmFree(pArgs->pRasDialParams); pArgs->pRasDialParams = NULL; } if (pArgs->pszCurrentAccessPoint) { CmFree(pArgs->pszCurrentAccessPoint); pArgs->pszCurrentAccessPoint = NULL; } // // Cleanup Help by killing the help file window if any and releasing the help file // string. // if (pArgs->pszHelpFile) { CmWinHelp((HWND)NULL, (HWND)NULL, pArgs->pszHelpFile, HELP_QUIT, 0); CmFree(pArgs->pszHelpFile); pArgs->pszHelpFile = NULL; } // // Release Ini objects // ReleaseIniObjects(pArgs); // // Release OLE links if any // if (pArgs->olsOle32Link.hInstOle32 && pArgs->olsOle32Link.pfnOleUninitialize) { pArgs->olsOle32Link.pfnOleUninitialize(); } UnlinkFromOle32(&pArgs->olsOle32Link); // // Release stats and table classes // if (pArgs->pConnStatistics) { delete pArgs->pConnStatistics; } if (pArgs->pConnTable) { MYVERIFY(SUCCEEDED(pArgs->pConnTable->Close())); delete pArgs->pConnTable; } } // // Releases any resources allocated during initialization // void OnMainExit(ArgsStruct *pArgs) { // // Release bitmap resources for main dlg // ReleaseBitmapData(&pArgs->BmpData); if (pArgs->hMasterPalette) { UnrealizeObject(pArgs->hMasterPalette); DeleteObject(pArgs->hMasterPalette); pArgs->hMasterPalette = NULL; } // // Release icon resources // if (pArgs->hBigIcon) { DeleteObject(pArgs->hBigIcon); pArgs->hBigIcon = NULL; } if (pArgs->hSmallIcon) { DeleteObject(pArgs->hSmallIcon); pArgs->hSmallIcon = NULL; } if (pArgs->pszResetPasswdExe) { CmFree(pArgs->pszResetPasswdExe); pArgs->pszResetPasswdExe = NULL; } if (pArgs->uiCurrentDnsTunnelAddr) { CmFree(pArgs->pucDnsTunnelIpAddr_list); pArgs->pucDnsTunnelIpAddr_list = NULL; } if (pArgs->rgwRandomDnsIndex) { CmFree(pArgs->rgwRandomDnsIndex); pArgs->rgwRandomDnsIndex = NULL; } } // // GetPhoneByIdx: get phone number, etc. information from .cmp file // LPTSTR GetPhoneByIdx(ArgsStruct *pArgs, UINT nIdx, LPTSTR *ppszDesc, LPTSTR *ppszDUN, LPDWORD pdwCountryID, LPTSTR *ppszRegionName, LPTSTR *ppszServiceType, LPTSTR *ppszPhoneBookFile, LPTSTR *ppszCanonical, DWORD *pdwPhoneInfoFlags) { MYDBGASSERT(ppszCanonical); MYDBGASSERT(pdwPhoneInfoFlags); // // Note: ppszCanonical and pdwPhoneInfoFlags are now required parameters. // While somewhat unfortunate, this is necessary to retain the integrity // of the retrieved data as legacy handling forces us to return data // that may not be an exact representation of the profile contents. // For example, the ppszCanonical and pdwPhoneInfoFlags value may be modified // overridden in certain situations. Please see comments below for details. // int nMaxPhoneLen = 0; BOOL bTmp = FALSE; // service profile: .CMP file CIni iniTmp(pArgs->piniProfile->GetHInst(),pArgs->piniProfile->GetFile(), pArgs->piniProfile->GetRegPath()); iniTmp.SetEntryFromIdx(nIdx); // // Set the read flags // if (pArgs->dwGlobalUserInfo & CM_GLOBAL_USER_INFO_READ_ICS_DATA) { LPTSTR pszICSDataReg = BuildICSDataInfoSubKey(pArgs->szServiceName); if (pszICSDataReg) { iniTmp.SetReadICSData(TRUE); iniTmp.SetICSDataPath(pszICSDataReg); } CmFree(pszICSDataReg); } LPTSTR pszTmp = iniTmp.GPPS(c_pszCmSection,c_pszCmEntryPhonePrefix); if (ppszDesc) { *ppszDesc = iniTmp.GPPS(c_pszCmSection,c_pszCmEntryPhoneDescPrefix); } if (ppszDUN) { *ppszDUN = iniTmp.GPPS(c_pszCmSection,c_pszCmEntryPhoneDunPrefix); } if (pdwCountryID) { *pdwCountryID = iniTmp.GPPI(c_pszCmSection,c_pszCmEntryPhoneCountryPrefix); } if (ppszPhoneBookFile) { LPTSTR pszPb = iniTmp.GPPS(c_pszCmSection,c_pszCmEntryPhoneSourcePrefix); // // If the value is empty, just store the ptr // if ((!*pszPb)) { *ppszPhoneBookFile = pszPb; } else { *ppszPhoneBookFile = CmConvertRelativePath(pArgs->piniService->GetFile(), pszPb); CmFree(pszPb); } } if (ppszRegionName) { *ppszRegionName = iniTmp.GPPS(c_pszCmSection, c_pszCmEntryRegion); } if (ppszServiceType) { *ppszServiceType = iniTmp.GPPS(c_pszCmSection, c_pszCmEntryServiceType); } // // Get the extended form of the telephone number. // if (ppszCanonical) { *ppszCanonical = iniTmp.GPPS(c_pszCmSection, c_pszCmEntryPhoneCanonical); } // // Set the phoneinfo flags // if (pdwPhoneInfoFlags) { *pdwPhoneInfoFlags = 0; // // Get the dial as long distance flag. Check CMS if no value found. // int iTmp = iniTmp.GPPI(c_pszCmSection, c_pszCmEntryUseDialingRules, -1); if (-1 == iTmp) { iTmp = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryUseDialingRules, 1); } if (iTmp) { *pdwPhoneInfoFlags |= PIF_USE_DIALING_RULES; } } // // Truncate phone string if we have one. // Note: Admin can override our default, but we // must stay within RAS_MaxPhoneNumber chars. // if (pszTmp && *pszTmp) { int nDefaultPhoneLen = (OS_NT ? MAX_PHONE_LENNT : MAX_PHONE_LEN95); nMaxPhoneLen = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxPhoneNumber, nDefaultPhoneLen); nMaxPhoneLen = __min(nMaxPhoneLen, RAS_MaxPhoneNumber); if ((int)lstrlenU(pszTmp) > nMaxPhoneLen) { pszTmp[nMaxPhoneLen] = TEXT('\0'); } } // // Special handling for the case where we have a Phone number // but the CanonicalPhone value doesn't exist. This indicates // that its either a legacy profile or a hand-edit. // if (*pszTmp && ppszCanonical && *ppszCanonical && (!(**ppszCanonical))) { // // This block is for handling LEGACY numbers only. If we detect a // canonically formatted number (begins with "+"), then we re-format // the number to fit our new scheme. Hand-edits are not modified, // but PIF_USE_DIALING_RULES is turned off, which overrides the // default setting for the flag (if any) specified in // the .CMS // if (pszTmp == CmStrchr(pszTmp, TEXT('+'))) { *pdwPhoneInfoFlags |= PIF_USE_DIALING_RULES; if (*ppszCanonical) { CmFree(*ppszCanonical); } *ppszCanonical = CmStrCpyAlloc(pszTmp); StripCanonical(pszTmp); } else { *pdwPhoneInfoFlags &= ~PIF_USE_DIALING_RULES; // #284702 } } return (pszTmp); } // write phone number dialing options to .CMP file void PutPhoneByIdx(ArgsStruct *pArgs, UINT nIdx, LPCTSTR pszPhone, LPCTSTR pszDesc, LPCTSTR pszDUN, DWORD dwCountryID, LPCTSTR pszRegionName, LPCTSTR pszServiceType, LPCTSTR pszPhoneBookFile, LPCTSTR pszCanonical, DWORD dwPhoneInfoFlags) { CIni iniTmp(pArgs->piniProfile->GetHInst(), pArgs->piniProfile->GetFile(), pArgs->piniProfile->GetRegPath()); iniTmp.SetEntryFromIdx(nIdx); // // Set the write flags // if (pArgs->dwGlobalUserInfo & CM_GLOBAL_USER_INFO_WRITE_ICS_DATA) { LPTSTR pszICSDataReg = BuildICSDataInfoSubKey(pArgs->szServiceName); if (pszICSDataReg) { iniTmp.SetWriteICSData(TRUE); iniTmp.SetICSDataPath(pszICSDataReg); } CmFree(pszICSDataReg); } // // Store the raw form of the number // iniTmp.WPPS(c_pszCmSection, c_pszCmEntryPhonePrefix, pszPhone); // // Store the canonical form of the number // iniTmp.WPPS(c_pszCmSection, c_pszCmEntryPhoneCanonical, pszCanonical); iniTmp.WPPS(c_pszCmSection, c_pszCmEntryPhoneDescPrefix, pszDesc); iniTmp.WPPS(c_pszCmSection, c_pszCmEntryPhoneDunPrefix, pszDUN); iniTmp.WPPI(c_pszCmSection, c_pszCmEntryPhoneCountryPrefix, dwCountryID); iniTmp.WPPS(c_pszCmSection, c_pszCmEntryRegion, pszRegionName); iniTmp.WPPS(c_pszCmSection, c_pszCmEntryServiceType, pszServiceType); // // If there is a phonebookfile path, convert it to relative form // if (pszPhoneBookFile && *pszPhoneBookFile) { LPTSTR pszTmp = ReducePathToRelative(pArgs, pszPhoneBookFile); if (pszTmp) { iniTmp.WPPS(c_pszCmSection, c_pszCmEntryPhoneSourcePrefix, pszTmp); } CmFree(pszTmp); } iniTmp.WPPB(c_pszCmSection, c_pszCmEntryUseDialingRules, (dwPhoneInfoFlags & PIF_USE_DIALING_RULES)); } //+---------------------------------------------------------------------------- // // Function: LoadPhoneInfoFromProfile // // Synopsis: Load phone number information for profile to the dial info structure // // Arguments: ArgsStruct *pArgs - // // Returns: Nothing // // History: fengsun Created Header 3/5/98 // //+---------------------------------------------------------------------------- void LoadPhoneInfoFromProfile(ArgsStruct *pArgs) { for (int nPhoneIdx=0; nPhoneIdxaDialInfo[nPhoneIdx].szPhoneNumber, CELEMS(pArgs->aDialInfo[nPhoneIdx].szPhoneNumber), pszPhone, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); pArgs->aDialInfo[nPhoneIdx].dwCountryID = dwCountryID; (void)StringCchCopyEx(pArgs->aDialInfo[nPhoneIdx].szDUN, CELEMS(pArgs->aDialInfo[nPhoneIdx].szDUN), pszDUN, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); (void)StringCchCopyEx(pArgs->aDialInfo[nPhoneIdx].szPhoneBookFile, CELEMS(pArgs->aDialInfo[nPhoneIdx].szPhoneBookFile), pszPhoneBookFile, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); (void)StringCchCopyEx(pArgs->aDialInfo[nPhoneIdx].szDesc, CELEMS(pArgs->aDialInfo[nPhoneIdx].szDesc), pszDesc, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); (void)StringCchCopyEx(pArgs->aDialInfo[nPhoneIdx].szRegionName, CELEMS(pArgs->aDialInfo[nPhoneIdx].szRegionName), pszRegionName, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); (void)StringCchCopyEx(pArgs->aDialInfo[nPhoneIdx].szServiceType, CELEMS(pArgs->aDialInfo[nPhoneIdx].szServiceType), pszServiceType, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); (void)StringCchCopyEx(pArgs->aDialInfo[nPhoneIdx].szCanonical, CELEMS(pArgs->aDialInfo[nPhoneIdx].szCanonical), pszCanonical, NULL, NULL, STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE); pArgs->aDialInfo[nPhoneIdx].dwPhoneInfoFlags = dwPhoneInfoFlags; // // Cleanup // CmFree(pszDUN); CmFree(pszPhone); CmFree(pszDesc); CmFree(pszPhoneBookFile); CmFree(pszRegionName); CmFree(pszServiceType); CmFree(pszCanonical); } // for loop } //+---------------------------------------------------------------------------- // // Function: LoadDialInfo // // Synopsis: load dialup information // // Arguments: ArgsStruct *pArgs - Ptr to glbal Args struct // HWND hwndDlg - HWND of main dialog // BOOL fInstallModem - Whether we should check modem isntall // BOOL fAlwaysMunge - Whether we should munge the phone number // // Returns: DWORD - ERROR_SUCCESS if load successfuly // ERROR_PORT_NOT_AVAILABLE if can not find any modem // ERROR_BAD_PHONE_NUMBER either there is no primary phone # // or failed to convert it to dialable # // // History: 10/24/97 fengsun Created Header and change return type to DWORD // 02/08/99 nickball Added fAlwaysMunge // //+---------------------------------------------------------------------------- DWORD LoadDialInfo(ArgsStruct *pArgs, HWND hwndDlg, BOOL fInstallModem, BOOL fAlwaysMunge) { DWORD dwRet = ERROR_SUCCESS; if (pArgs->bDialInfoLoaded) { if (pArgs->aDialInfo[0].szDialablePhoneNumber[0] == TEXT('\0') && pArgs->aDialInfo[1].szDialablePhoneNumber[0] == TEXT('\0')) { return ERROR_BAD_PHONE_NUMBER; } else { // // If fAlways munge is set, then stick around. // if (!fAlwaysMunge) { return ERROR_SUCCESS; } } } // // Don't need to repeat ourselves // if (!pArgs->bDialInfoLoaded) { pArgs->fNoDialingRules = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmNoDialingRules); // // Do a full test on just the modem // if (fInstallModem) { pArgs->dwExitCode = CheckAndInstallComponents(CC_MODEM, hwndDlg, pArgs->szServiceName); if (pArgs->dwExitCode != ERROR_SUCCESS) { dwRet = ERROR_PORT_NOT_AVAILABLE; goto LoadDialInfoExit; } } // // Establish TAPI link before we continue // if (!LinkToTapi(&pArgs->tlsTapiLink, "TAPI32") ) { // // Link to TAPI failed. // If unattended, return with failure. // Otherwise, try to install components and LinkToTapi again // pArgs->dwExitCode = ERROR_PORT_NOT_AVAILABLE; if (!(pArgs->dwFlags & FL_UNATTENDED)) { pArgs->dwExitCode = CheckAndInstallComponents(CC_MODEM | CC_RNA | CC_RASRUNNING, hwndDlg, pArgs->szServiceName); } if (pArgs->dwExitCode != ERROR_SUCCESS || !LinkToTapi(&pArgs->tlsTapiLink, "TAPI32")) { pArgs->szDeviceType[0] = TEXT('\0'); pArgs->szDeviceName[0] = TEXT('\0'); dwRet = ERROR_PORT_NOT_AVAILABLE; goto LoadDialInfoExit; } } // // RasEnumDevice and LineInitialize is SLOW. It takes 50% of the start-up time // if (!PickModem(pArgs, pArgs->szDeviceType, pArgs->szDeviceName)) { // // Because pick modem failed we need to check if we have RAS/Modem installed // ClearComponentsChecked(); // // No modem is installed. // If unattended or caller does not want to install modem, return with failure. // Otherwise, try to install the modem and call pick modem again // pArgs->dwExitCode = ERROR_PORT_NOT_AVAILABLE; if (!(pArgs->dwFlags & FL_UNATTENDED) && fInstallModem) { pArgs->dwExitCode = CheckAndInstallComponents(CC_MODEM | CC_RNA | CC_RASRUNNING, hwndDlg, pArgs->szServiceName); } if (pArgs->dwExitCode != ERROR_SUCCESS || !PickModem(pArgs, pArgs->szDeviceType, pArgs->szDeviceName)) { pArgs->szDeviceType[0] = TEXT('\0'); pArgs->szDeviceName[0] = TEXT('\0'); dwRet = ERROR_PORT_NOT_AVAILABLE; goto LoadDialInfoExit; } } } // // See if munge is required and Cleanup as needed // if (!pArgs->bDialInfoLoaded || TRUE == fAlwaysMunge) { MungeDialInfo(pArgs); pArgs->bDialInfoLoaded = TRUE; } if (pArgs->aDialInfo[0].szDialablePhoneNumber[0] == TEXT('\0') && pArgs->aDialInfo[1].szDialablePhoneNumber[0] == TEXT('\0')) { dwRet = ERROR_BAD_PHONE_NUMBER; } LoadDialInfoExit: return dwRet; } //+---------------------------------------------------------------------------- // // Function: MungeDialInfo // // Synopsis: Encapsulates the munging of the phone numbers prior to dialing // // Arguments: ArgsStruct *pArgs - Ptr to global Args struct // // Returns: Nothing - Check Dialable string and fNeedConfigureTapi // // History: 02/08/99 nickball Created - pulled from LoadDialInfo // //+---------------------------------------------------------------------------- VOID MungeDialInfo(ArgsStruct *pArgs) { for (int nPhoneIdx=0; nPhoneIdxfNoDialingRules) { lstrcpynU(pArgs->aDialInfo[nPhoneIdx].szDialablePhoneNumber, pArgs->aDialInfo[nPhoneIdx].szPhoneNumber, CELEMS(pArgs->aDialInfo[nPhoneIdx].szDialablePhoneNumber)); lstrcpynU(pArgs->aDialInfo[nPhoneIdx].szDisplayablePhoneNumber, pArgs->aDialInfo[nPhoneIdx].szPhoneNumber, CELEMS(pArgs->aDialInfo[nPhoneIdx].szDisplayablePhoneNumber)); pArgs->aDialInfo[nPhoneIdx].szCanonical[0] = TEXT('\0'); continue; } LPTSTR pszDialableString= NULL; // // Retrieve the number based upon dialing rules and munge it. // LPTSTR pszPhone; if (pArgs->aDialInfo[nPhoneIdx].dwPhoneInfoFlags & PIF_USE_DIALING_RULES) { pszPhone = CmStrCpyAlloc(pArgs->aDialInfo[nPhoneIdx].szCanonical); } else { pszPhone = CmStrCpyAlloc(pArgs->aDialInfo[nPhoneIdx].szPhoneNumber); } if (pszPhone && pszPhone[0]) { // // If we can't munge the number, display an error // if (pArgs->szDeviceName[0] && ERROR_SUCCESS != MungePhone(pArgs->szDeviceName, &pszPhone, &pArgs->tlsTapiLink, g_hInst, pArgs->aDialInfo[nPhoneIdx].dwPhoneInfoFlags & PIF_USE_DIALING_RULES, &pszDialableString, pArgs->fAccessPointsEnabled)) { CmFree(pszPhone); pszPhone = CmStrCpyAlloc(TEXT("")); // CmFmtMsg(g_hInst,IDMSG_CANTFORMAT); pszDialableString = CmStrCpyAlloc(TEXT("")); // CmFmtMsg(g_hInst,IDMSG_CANTFORMAT); } else if (!pszDialableString || pszDialableString[0] == '\0') { // // So what happened now? pszPhone is not empty, but after // we munge the phone, which means applying TAPI rules, // pszDialbleString becomes empty. This means only one // thing: TAPI isn't intialized. // // Note: If you uninstall TAPI between launching the app. // and pressing connect, all bets are off with the above. // // This flag will be reset in CheckTapi(), which will put // up a TAPI configuration dialog and ask the user to fill // up such information // pArgs->fNeedConfigureTapi = TRUE; } } // Copy the munged number // // Unless explicitly disabled we always apply TAPI rules // in order to pick up TONE/PULSE, etc. // if (NULL != pszDialableString) { lstrcpynU(pArgs->aDialInfo[nPhoneIdx].szDialablePhoneNumber, pszDialableString, CELEMS(pArgs->aDialInfo[nPhoneIdx].szDialablePhoneNumber)); lstrcpynU(pArgs->aDialInfo[nPhoneIdx].szDisplayablePhoneNumber, pszPhone, CELEMS(pArgs->aDialInfo[nPhoneIdx].szDisplayablePhoneNumber)); } else { if (NULL != pszPhone) { // // Just do it on WIN32 because our TAPI checks were done above // lstrcpynU(pArgs->aDialInfo[nPhoneIdx].szDialablePhoneNumber, pszPhone, CELEMS(pArgs->aDialInfo[nPhoneIdx].szDialablePhoneNumber)); lstrcpynU(pArgs->aDialInfo[nPhoneIdx].szDisplayablePhoneNumber, pszPhone, CELEMS(pArgs->aDialInfo[nPhoneIdx].szDisplayablePhoneNumber)); } } CmFree(pszPhone); CmFree(pszDialableString); } // for loop } //+--------------------------------------------------------------------------- // // Function: LoadHelpFileInfo // // Synopsis: Load the help file name // // Arguments: pArgs [the ptr to ArgsStruct] // // Returns: NONE // // History: henryt Created 3/5/97 // byao Modified 3/20/97 to handle empty helpfile string //---------------------------------------------------------------------------- void LoadHelpFileInfo(ArgsStruct *pArgs) { MYDBGASSERT(pArgs); // // Look for a custom helpfile name, otherwise use default. // LPTSTR pszTmp = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryHelpFile); if (NULL == pszTmp || 0 == pszTmp[0]) { CmFree(pszTmp); pszTmp = CmStrCpyAlloc(c_pszDefaultHelpFile); } // // Make sure that any relative path is converted to full // pArgs->pszHelpFile = CmConvertRelativePath(pArgs->piniService->GetFile(), pszTmp); CmFree(pszTmp); } // // CopyPhone: // void CopyPhone(ArgsStruct *pArgs, LPRASENTRY preEntry, DWORD dwEntry) { LPTSTR pszPhone = NULL; LPTSTR pszCanonical = NULL; LPTSTR pszTmp; LPTSTR pszDescription = NULL; BOOL Setcountry = FALSE; DWORD dwPhoneInfoFlags = 0; pszPhone = GetPhoneByIdx(pArgs,(UINT) dwEntry, &pszDescription, NULL, NULL, NULL, NULL, NULL, &pszCanonical, &dwPhoneInfoFlags); // // If "Use Dialing Rules" turn of CountryAndAreaCodes option // if (dwPhoneInfoFlags & PIF_USE_DIALING_RULES) { // // We want to use dialing rules, so parse the canonical form // of the number to get the country and area codes for the entry // pszTmp = CmStrchr(pszCanonical,TEXT('+')); if (pszTmp) { preEntry->dwCountryCode = CmAtol(pszTmp+1); // // NOTE: Currently CM uses code and ID interchangeably // The countryID value in the .CMP is actually the country // code used when constructing the phone number in its // canonical format. This is probably not entirely correct // but we maitain consistency with it here by using the // country code parsed from the number as the country ID. // preEntry->dwCountryID = preEntry->dwCountryCode; preEntry->dwfOptions |= RASEO_UseCountryAndAreaCodes; Setcountry = TRUE; } if (Setcountry) { pszTmp = CmStrchr(pszCanonical,'('); //strip out area code if (pszTmp) { (void)StringCchPrintfEx(preEntry->szAreaCode, CELEMS(preEntry->szAreaCode), NULL, NULL, (STRSAFE_IGNORE_NULLS | STRSAFE_NULL_ON_FAILURE), TEXT("%u"), CmAtol(pszTmp+1)); } pszTmp = CmStrchr(pszCanonical,')'); if (pszTmp) { ++pszTmp; while(*pszTmp == ' ') ++pszTmp; //remove whitespace } else { // no area code preEntry->szAreaCode[0]=TEXT('\0'); pszTmp = CmStrchr(pszCanonical,' '); if (pszTmp) { while(*pszTmp == ' ') ++pszTmp; // skip past space - may need MBCS change } } } } else { // // Use the straight up phone number and don't apply rules // preEntry->dwfOptions &= ~RASEO_UseCountryAndAreaCodes; pszTmp = pszPhone; } if ((NULL != pszTmp) && *pszTmp) { lstrcpynU(preEntry->szLocalPhoneNumber, pszTmp, CELEMS(preEntry->szLocalPhoneNumber)); } else { lstrcpynU(preEntry->szLocalPhoneNumber, TEXT(" "), CELEMS(preEntry->szLocalPhoneNumber));//prevent zero from appearing } CmFree(pszPhone); CmFree(pszCanonical); CmFree(pszDescription); } //+---------------------------------------------------------------------------- // // Function: AppendStatusPane // // Synopsis: Append the text to the main dialog status window // // Arguments: HWND hwndDlg - The main dialog window handle // DWORD dwMsgId - The resource id of the message // // Returns: Nothing // // History: Created Header 10/24/97 // //+---------------------------------------------------------------------------- void AppendStatusPane(HWND hwndDlg, DWORD dwMsgId) { LPTSTR pszTmp = CmFmtMsg(g_hInst,dwMsgId); if (pszTmp != NULL) { AppendStatusPane(hwndDlg,pszTmp); CmFree(pszTmp); } } // // AppendStatusPane: Update the original status, append new message 'pszMsg' // at the end // void AppendStatusPane(HWND hwndDlg, LPCTSTR pszMsg) { size_t nLines; // // Get the existing message // LPTSTR pszStatus = CmGetWindowTextAlloc(hwndDlg, IDC_MAIN_STATUS_DISPLAY); LPTSTR pszTmp = CmStrrchr(pszStatus, TEXT('\n')); if (!pszTmp) { // empty message, so simply display 'pszMsg' CmFree(pszStatus); SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY,pszMsg); // // force an update right away // UpdateWindow(GetDlgItem(hwndDlg, IDC_MAIN_STATUS_DISPLAY)); return; } pszTmp[1] = 0; CmStrCatAlloc(&pszStatus,pszMsg); // append pszMsg at the end of old message nLines = 0; pszTmp = pszStatus + lstrlenU(pszStatus); while (pszTmp != pszStatus) { pszTmp--; if (*pszTmp == '\n') { if (++nLines == 2) { lstrcpyU(pszStatus,pszTmp+1); break; } } } SetDlgItemTextU(hwndDlg,IDC_MAIN_STATUS_DISPLAY,pszStatus); SendDlgItemMessageU(hwndDlg,IDC_MAIN_STATUS_DISPLAY,EM_SCROLL,SB_PAGEDOWN,0); CmFree(pszStatus); // // force an update right away // UpdateWindow(GetDlgItem(hwndDlg, IDC_MAIN_STATUS_DISPLAY)); } // bitmap logo loading code - took this out of LoadFromFile so it can // be called in multiple cases - like when the FS OC loading code // fails, we can degrade gracefully with this. VOID LoadLogoBitmap(ArgsStruct * pArgs, HWND hwndDlg) { LPTSTR pszTmp; pszTmp = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryLogo); if (*pszTmp) { // // Make sure we have a full path (if appropriate) and load logo bitmap // LPTSTR pszFile = CmConvertRelativePath(pArgs->piniService->GetFile(), pszTmp); pArgs->BmpData.hDIBitmap = CmLoadBitmap(g_hInst, pszFile); CmFree(pszFile); } CmFree(pszTmp); if (!pArgs->BmpData.hDIBitmap) { pArgs->BmpData.hDIBitmap = CmLoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_APP)); } // // If we have a handle, create a new Device Dependent bitmap // if (pArgs->BmpData.hDIBitmap) { pArgs->BmpData.phMasterPalette = &pArgs->hMasterPalette; pArgs->BmpData.bForceBackground = TRUE; // paint as a background app if (CreateBitmapData(pArgs->BmpData.hDIBitmap, &pArgs->BmpData, hwndDlg, TRUE)) { SendDlgItemMessageU(hwndDlg,IDC_MAIN_BITMAP,STM_SETIMAGE,IMAGE_BITMAP, (LPARAM) &pArgs->BmpData); } } } const LONG MAX_SECTION = 512; HRESULT LoadFutureSplash(ArgsStruct * pArgs, HWND hwndDlg) { // set up the Future Splash OC container. LPCTSTR pszFile = pArgs->piniBoth->GetFile(); TCHAR achSections[MAX_SECTION] = {0}; HRESULT hr; LPTSTR pszVal = NULL; LPTSTR pszTmp = NULL; LPICMOCCtr pCtr; pArgs->pCtr = new CICMOCCtr(hwndDlg, ::GetDlgItem(hwndDlg, IDC_MAIN_BITMAP)); if (!pArgs->pCtr) { goto MemoryError; } if (!pArgs->pCtr->Initialized()) { hr = E_FAIL; goto Cleanup; } pCtr = pArgs->pCtr; if (!::GetPrivateProfileStringU( c_pszCmSectionAnimatedLogo, 0, TEXT(""), achSections, NElems(achSections), pszFile)) { hr = E_FAIL; goto Cleanup; } pszVal = (LPTSTR) CmMalloc(INTERNET_MAX_URL_LENGTH * sizeof(TCHAR)); if (NULL == pszVal) { hr = E_OUTOFMEMORY; goto Cleanup; } pszTmp = achSections; while (pszTmp[0]) { // if this fails, we keep on looping, looking for // the next one. if (::GetPrivateProfileStringU( c_pszCmSectionAnimatedLogo, pszTmp, TEXT(""), pszVal, NElems(pszVal), pszFile)) { if (lstrcmpiU(pszTmp, c_pszCmEntryAniMovie) == 0) // is this the 'movie' entry? { // // Build full path from .CMP and relative path // LPTSTR pszMovieFileName = CmBuildFullPathFromRelative(pArgs->piniProfile->GetFile(), pszVal); if (!pszMovieFileName) { hr = S_FALSE; CmFree(pszMovieFileName); goto Cleanup; } // // Does this file exist? // if (FALSE == FileExists(pszMovieFileName)) { hr = S_FALSE; CmFree(pszMovieFileName); goto Cleanup; } lstrcpyU(pszVal, pszMovieFileName); // store the full pathname back CmFree(pszMovieFileName); } hr = pCtr->AddPropertyToBag(pszTmp, pszVal); if (S_OK != hr) goto Cleanup; } // get the next key name. pszTmp += (lstrlenU(pszTmp) + 1); } // create the Future Splash OC. hr = pCtr->CreateFSOC(&pArgs->olsOle32Link); if (S_OK != hr) { goto Cleanup; } // now, do the state mappings, no matter what happens, we won't // fail on this. just keep on going. pCtr->SetFrameMapping(PS_Interactive, ::GetPrivateProfileIntU(c_pszCmSectionAnimatedActions, c_pszCmEntryAniPsInteractive, -1, pszFile)); pCtr->SetFrameMapping(PS_Dialing, ::GetPrivateProfileIntU(c_pszCmSectionAnimatedActions, c_pszCmEntryAniPsDialing0, -1, pszFile)); pCtr->SetFrameMapping(PS_RedialFrame, ::GetPrivateProfileIntU(c_pszCmSectionAnimatedActions, c_pszCmEntryAniPsDialing1, -1, pszFile)); pCtr->SetFrameMapping(PS_Pausing, ::GetPrivateProfileIntU(c_pszCmSectionAnimatedActions, c_pszCmEntryAniPsPausing, -1, pszFile)); pCtr->SetFrameMapping(PS_Authenticating, ::GetPrivateProfileIntU(c_pszCmSectionAnimatedActions, c_pszCmEntryAniPsAuthenticating, -1, pszFile)); pCtr->SetFrameMapping(PS_Online, ::GetPrivateProfileIntU(c_pszCmSectionAnimatedActions, c_pszCmEntryAniPsOnline, -1, pszFile)); pCtr->SetFrameMapping(PS_TunnelDialing, ::GetPrivateProfileIntU(c_pszCmSectionAnimatedActions, c_pszCmEntryAniPsTunnel, -1, pszFile)); pCtr->SetFrameMapping(PS_Error, ::GetPrivateProfileIntU(c_pszCmSectionAnimatedActions, c_pszCmEntryAniPsError, -1, pszFile)); Cleanup: if (pszVal) { CmFree(pszVal); } return hr; MemoryError: hr = E_OUTOFMEMORY; goto Cleanup; } //+--------------------------------------------------------------------------- // // Function: LoadProperties // // Synopsis: This func loads CM Properties from cmp/cms, registry, password // cache, etc, into its internal variables. This func should // only be called once. This should not be specific to the main // sign-in dlg. DO NOT do any icon/bitmap stuff, dlg specific // stuff here. // // Arguments: pArgs [the ptr to ArgsStruct] // // Returns: NONE // // History: henryt Created 5/2/97 // // t-urama Modified 08/02/00 Added Access Points //---------------------------------------------------------------------------- void LoadProperties( ArgsStruct *pArgs ) { LPTSTR pszTmp = NULL; LPTSTR pszUserName = NULL; UINT nTmp; CMTRACE(TEXT("Begin LoadProperties()")); // // First make sure we can use the RAS CredStore // This flag is used in the calls below // if (OS_NT5) { pArgs->bUseRasCredStore = TRUE; } // // Upgrade userinfo if necessary. Note that we have // an upgrade from CM 1.0/1.1 cmp data and we also // have an upgrade of CM 1.2 registry data to // the method used in CM 1.3 on Win2k which uses both // the registry and RAS credential storage. // int iUpgradeType = NeedToUpgradeUserInfo(pArgs); if (c_iUpgradeFromRegToRas == iUpgradeType) { UpgradeUserInfoFromRegToRasAndReg(pArgs); } else if (c_iUpgradeFromCmp == iUpgradeType) { UpgradeUserInfoFromCmp(pArgs); } // // Need to refresh Credential support. The TRUE flag also sets the current creds // type inside the function. If an error occurs we can keep executing. // if(FALSE == RefreshCredentialTypes(pArgs, TRUE)) { CMTRACE(TEXT("LoadProperties() - Error refreshing credential types.")); } if (IsTunnelEnabled(pArgs)) { // // do we use the same username/password for tunneling? // This value is set by ISP, CM does not change it // pArgs->fUseSameUserName = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryUseSameUserName); // // read in inet username // Special case where the same user name isn't being used, and internet globals don't exist // Then we have to read the user name from the user creds store in order to pre-populate // DWORD dwRememberedCredType = pArgs->dwCurrentCredentialType; pszUserName = NULL; if ((FALSE == pArgs->fUseSameUserName) && (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) && (FALSE == (BOOL)(CM_EXIST_CREDS_INET_GLOBAL & pArgs->dwExistingCredentials))) { pArgs->dwCurrentCredentialType = CM_CREDS_USER; } GetUserInfo(pArgs, UD_ID_INET_USERNAME, (PVOID*)&pszUserName); // // Restore credential store // pArgs->dwCurrentCredentialType = dwRememberedCredType; if (pszUserName) { // // check username length // nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxUserName, UNLEN); if ((UINT)lstrlenU(pszUserName) > __min(UNLEN, nTmp)) { CmFree(pszUserName); pArgs->szInetUserName[0] = TEXT('\0'); SaveUserInfo(pArgs, UD_ID_INET_USERNAME, (PVOID)pArgs->szInetUserName); } else { lstrcpyU(pArgs->szInetUserName, pszUserName); CmFree(pszUserName); } } else { *pArgs->szInetUserName = TEXT('\0'); } // // Read in inet password unless we are reconnecting in which case, we // already have the correct password, and we want to use it and dial // automatically. // if (!(pArgs->dwFlags & FL_RECONNECT)) { LPTSTR pszPassword = NULL; GetUserInfo(pArgs, UD_ID_INET_PASSWORD, (PVOID*)&pszPassword); if (!pszPassword) { CmWipePassword(pArgs->szInetPassword); } else { nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxPassword, PWLEN); if ((UINT)lstrlenU(pszPassword) > __min(PWLEN, nTmp)) { CmFree(pszPassword); pszPassword = CmStrCpyAlloc(TEXT("")); } lstrcpyU(pArgs->szInetPassword, pszPassword); CmEncodePassword(pArgs->szInetPassword); // Never leave a PWD in plain text on heap CmWipePassword(pszPassword); CmFree(pszPassword); } } } // // The presence of either lpRasNoUser or lpEapLogonInfo indicates // that we retrieved credentials via WinLogon. We ignore cached // creds in this situation. // if ((!pArgs->lpRasNoUser) && (!pArgs->lpEapLogonInfo)) { // // get username, domain, etc. from CMS file // GetUserInfo(pArgs, UD_ID_USERNAME, (PVOID*)&pszUserName); if (pszUserName) { // // check username length // nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxUserName, UNLEN); if ((UINT)lstrlenU(pszUserName) > __min(UNLEN, nTmp)) { CmFree(pszUserName); pszUserName = CmStrCpyAlloc(TEXT("")); SaveUserInfo(pArgs, UD_ID_USERNAME, (PVOID)pszUserName); } lstrcpyU(pArgs->szUserName, pszUserName); CmFree(pszUserName); } else { *pArgs->szUserName = TEXT('\0'); } // // Read in the standard password unless we are reconnecting in which case // we already have the correct password, and we want to use it and dial // automatically. // if (!(pArgs->dwFlags & FL_RECONNECT)) { pszTmp = NULL; GetUserInfo(pArgs, UD_ID_PASSWORD, (PVOID*)&pszTmp); if (pszTmp) { // // max length for user password // nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection,c_pszCmEntryMaxPassword,PWLEN); if ((UINT)lstrlenU(pszTmp) > __min(PWLEN,nTmp)) { CmFree(pszTmp); pszTmp = CmStrCpyAlloc(TEXT("")); } lstrcpyU(pArgs->szPassword, pszTmp); CmEncodePassword(pArgs->szPassword); // Never leave a PWD in plain text on heap CmWipePassword(pszTmp); CmFree(pszTmp); } else { CmWipePassword(pArgs->szPassword); } } // // Load domain info // LPTSTR pszDomain = NULL; GetUserInfo(pArgs, UD_ID_DOMAIN, (PVOID*)&pszDomain); if (pszDomain) { nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxDomain, DNLEN); if (nTmp <= 0) { nTmp = DNLEN; } if ((UINT)lstrlenU(pszDomain) > __min(DNLEN, nTmp)) { CmFree(pszDomain); pszDomain = CmStrCpyAlloc(TEXT("")); } lstrcpyU(pArgs->szDomain, pszDomain); CmFree(pszDomain); } else { *pArgs->szDomain = TEXT('\0'); } } // // fDialAutomatically, // fRememberMainPassword // if (pArgs->fHideDialAutomatically) { pArgs->fDialAutomatically = FALSE; } else { PVOID pv = &pArgs->fDialAutomatically; GetUserInfo(pArgs, UD_ID_NOPROMPT, &pv); } if (pArgs->fHideRememberPassword) { pArgs->fRememberMainPassword = FALSE; } else { // // For Win2K+ this gets trickier because we use the RAS cred store and // we know which creds were saved. Thus we need to modify this flag according // to what credentials we actually have, insted of what was retrieved from the registry/file. // This needs to be done after calling the function that refreshes credential types (above). // if (OS_NT5) { if (CM_CREDS_USER == pArgs->dwCurrentCredentialType) { pArgs->fRememberMainPassword = ((BOOL)(pArgs->dwExistingCredentials & CM_EXIST_CREDS_MAIN_USER)? TRUE: FALSE); } else { pArgs->fRememberMainPassword = ((BOOL)(pArgs->dwExistingCredentials & CM_EXIST_CREDS_MAIN_GLOBAL)? TRUE: FALSE); } } else { PVOID pv = &pArgs->fRememberMainPassword; GetUserInfo(pArgs, UD_ID_REMEMBER_PWD, &pv); } } // // remember non-tunnel password? // if (pArgs->fHideRememberInetPassword) { pArgs->fRememberInetPassword = FALSE; } else { // // For Win2K+ this gets trickier because we use the RAS cred store and // we know which creds were saved. Thus we need to modify this flag according // to what credentials we actually have, insted of what was retrieved from the registry/file. // This needs to be done after calling the function that refreshes credential types (above). // if (OS_NT5) { if (CM_CREDS_USER == pArgs->dwCurrentCredentialType) { pArgs->fRememberInetPassword = ((BOOL)(pArgs->dwExistingCredentials & CM_EXIST_CREDS_INET_USER)? TRUE: FALSE); } else { pArgs->fRememberInetPassword = ((BOOL)(pArgs->dwExistingCredentials & CM_EXIST_CREDS_INET_GLOBAL)? TRUE: FALSE); } } else { PVOID pv = &pArgs->fRememberInetPassword; GetUserInfo(pArgs, UD_ID_REMEMBER_INET_PASSWORD, &pv); } } // // Make sure that the passwords are empty if we don't want to remember them // unless we are reconnecting in which case we will just use what we have // from the previous connection. When the log on type is ICS don't want // to clear the passwords either. // if ((!(pArgs->dwFlags & FL_RECONNECT)) && (!pArgs->lpRasNoUser) && (!pArgs->lpEapLogonInfo) && (CM_LOGON_TYPE_ICS != pArgs->dwWinLogonType)) { // // NULL the password if dial-auto is disabled. // if (!pArgs->fRememberMainPassword) { CmWipePassword(pArgs->szPassword); } if (!pArgs->fRememberInetPassword) { CmWipePassword(pArgs->szInetPassword); } } // // has references // pszTmp = pArgs->piniService->GPPS(c_pszCmSectionIsp, c_pszCmEntryIspReferences); pArgs->fHasRefs = (pszTmp && *pszTmp ? TRUE : FALSE); CmFree(pszTmp); // // do we have valid pbk's? // pArgs->fHasValidTopLevelPBK = ValidTopLevelPBK(pArgs); if (pArgs->fHasRefs) { pArgs->fHasValidReferencedPBKs = ValidReferencedPBKs(pArgs); } // // Get idle settings for auto disconnect // 1.0 profile has a BOOL flag "Idle", if FALSE, IdleTimeout is ignored // if (!pArgs->piniBothNonFav->GPPB(c_pszCmSection, c_pszCmEntryIdle, TRUE)) { // // If this is a 1.0 profile and Idle==0, set IdleTimeout to 0, so CMMOM works correctly // pArgs->dwIdleTimeout = 0; // never timeout pArgs->piniProfile->WPPI(c_pszCmSection, c_pszCmEntryIdle, TRUE); // write back pArgs->piniProfile->WPPI(c_pszCmSection, c_pszCmEntryIdleTimeout, 0); // write back } else { pArgs->dwIdleTimeout = (int) pArgs->piniBothNonFav->GPPI(c_pszCmSection, c_pszCmEntryIdleTimeout, DEFAULT_IDLETIMEOUT); } // // get redial count // 1.0 profile has a BOOL flag "Redial", if FALSE, RedialCount is ignored // if (!pArgs->piniBothNonFav->GPPB(c_pszCmSection, c_pszCmEntryRedial, TRUE)) { // // If this is a 1.0 profile and Redial==0, set RetryCount to 0 // pArgs->nMaxRedials = 0; pArgs->piniBothNonFav->WPPI(c_pszCmSection, c_pszCmEntryRedialCount, 0); // write back } else { pArgs->nMaxRedials = (int) pArgs->piniBothNonFav->GPPI(c_pszCmSection, c_pszCmEntryRedialCount, DEFAULT_MAX_REDIALS); } // // Get the redial delay value // pArgs->nRedialDelay = (int) pArgs->piniService->GPPI(c_pszCmSection,c_pszCmEntryRedialDelay,DEFAULT_REDIAL_DELAY); // // should we enable ISDN dial on demand? // pArgs->dwIsdnDialMode = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryIsdnDialMode, CM_ISDN_MODE_SINGLECHANNEL); // // Get the Tapi location from the registry // if (pArgs->fAccessPointsEnabled) { pArgs->tlsTapiLink.dwTapiLocationForAccessPoint = pArgs->piniProfile->GPPI(c_pszCmSection, c_pszCmEntryTapiLocation); } CMTRACE(TEXT("End LoadProperties()")); } //+--------------------------------------------------------------------------- // // Function: LoadIconsAndBitmaps // // Synopsis: This func loads icon and bitmap settings. It should be part // of the main dlg init. // // Arguments: pArgs [the ptr to ArgsStruct] // hwndDlg [the main dlg] // // Returns: NONE // // History: henryt Copied from LoadFromFile() 5/2/97 // //---------------------------------------------------------------------------- void LoadIconsAndBitmaps( ArgsStruct *pArgs, HWND hwndDlg ) { LPTSTR pszTmp; UINT nTmp; // Load large icon name pszTmp = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryBigIcon); if (*pszTmp) { // // Make sure we have a full path (if appropriate) and load big icon // LPTSTR pszFile = CmConvertRelativePath(pArgs->piniService->GetFile(), pszTmp); pArgs->hBigIcon = CmLoadIcon(g_hInst, pszFile); CmFree(pszFile); } CmFree(pszTmp); // Use default (EXE) large icon if no user icon found if (!pArgs->hBigIcon) { pArgs->hBigIcon = CmLoadIcon(g_hInst, MAKEINTRESOURCE(IDI_APP)); } SendMessageU(hwndDlg,WM_SETICON,ICON_BIG,(LPARAM) pArgs->hBigIcon); // Load small icon name pszTmp = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntrySmallIcon); if (*pszTmp) { // // Make sure we have a full path (if appropriate) and load small icon // LPTSTR pszFile = CmConvertRelativePath(pArgs->piniService->GetFile(), pszTmp); pArgs->hSmallIcon = CmLoadSmallIcon(g_hInst, pszFile); CmFree(pszFile); } CmFree(pszTmp); // Use default (EXE) small icon if no user icon found if (!pArgs->hSmallIcon) { pArgs->hSmallIcon = CmLoadSmallIcon(g_hInst, MAKEINTRESOURCE(IDI_APP)); } SendMessageU(hwndDlg,WM_SETICON,ICON_SMALL,(LPARAM) pArgs->hSmallIcon); // // this is where the Bitmap gets loaded in. Check to see first if we're doing // the Future Splash thang. if so, no bitmap // // Note that we do not load FutureSplash if this is WinLogon. This is because // Future Splash Animations can have imbedded actions and thus could be used // to launch web pages, etc. from WinLogon as the system account. Definitely // would be a security hole. // nTmp = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryAnimatedLogo); if (!nTmp || IsLogonAsSystem()) { // // either there was no 'Animated Logo' entry, or it was 0, which means // we go ahead and load the bitmap. // LoadLogoBitmap(pArgs, hwndDlg); } else { // // if, for any reason, loading FS OC fails, go ahead and // degrade and load the logo bitmap. // if (S_OK != LoadFutureSplash(pArgs, hwndDlg)) { LoadLogoBitmap(pArgs, hwndDlg); } } } //+---------------------------------------------------------------------------- // // Function: DoRasHangup // // Synopsis: Hangup the given RAS device handle // // Arguments: prlsRasLink - Ptr to RAS linkage struct // hRasConnection - The RAS device to hangup // hwndDlg - The main dlg to display "Disconnecting .. " msg // Only used if fWaitForComplete is TRUE // Optional, default = NULL // fWaitForComplete - Whether to wait for Hangup to complete on 95 // If set to TRUE, will wait until hRasConnection // is invalid. Optional, default = FALSE // pfWaiting - Ptr to boolean value indicating our wait state // and whether Timer and Ras messages should be // ignored. Optional, default = NULL // // Returns: DWORD - ERROR_SUCCESS if success or error code // // Note: pArgs is removed so that the Disconnect path can use this function // thus concentrating the timing mess in one place. // // History: fengsun Created Header 10/22/97 // fengsun Add fWaitForComplete 12/18/97 // nickball Removed pArgs dependency // //+---------------------------------------------------------------------------- DWORD DoRasHangup(RasLinkageStruct *prlsRasLink, HRASCONN hRasConnection, HWND hwndDlg, BOOL fWaitForComplete, LPBOOL pfWaiting) { DWORD dwRes = ERROR_SUCCESS; MYDBGASSERT(hRasConnection != NULL); MYDBGASSERT(prlsRasLink->pfnHangUp != NULL); // // Do we need to check the return value // now that RAS is going to disconnect modem too? // dwRes = prlsRasLink->pfnHangUp(hRasConnection); CMTRACE1(TEXT("DoRasHangup() RasHangup() returned %u."), dwRes); // On Win32 RasHangup returns immediately, so loop until we // are certain that the disconnected state had been reached if ((dwRes == ERROR_SUCCESS) && prlsRasLink->pfnGetConnectStatus) { RASCONNSTATUS rcs; CMTRACE(TEXT("DoRasHangup() Waiting for hangup to complete")); // // On 95 Wait for HANGUP_TIMEOUT seconds // On NT wait until the connection is released // This will cause this to loop till the connection status // is RASCS_Disconnected // #define HANGUP_TIMEOUT 60 // timeout for 95 hangup if (pfWaiting) { // // Keep the message looping to avoid freezing CM // But do not handle WM_TIMER and RAS msg // MYDBGASSERT(!*pfWaiting); *pfWaiting = TRUE; } if (fWaitForComplete && hwndDlg) { // // Display the disconnecting message, if we have to wait // LPTSTR pszTmp = CmLoadString(g_hInst,IDMSG_DISCONNECTING); SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, pszTmp); CmFree(pszTmp); } DWORD dwStartWaitTime = GetTickCount(); HCURSOR hWaitCursor = LoadCursorU(NULL,IDC_WAIT); ZeroMemory(&rcs,sizeof(rcs)); rcs.dwSize = sizeof(rcs); while ((dwRes = prlsRasLink->pfnGetConnectStatus(hRasConnection,&rcs)) == ERROR_SUCCESS) { // // If it is NT, or do not need to wait for hangup to complete, // RASCS_Disconnected state is considered hangup complete // if (rcs.rasconnstate == RASCS_Disconnected && (!fWaitForComplete || OS_NT)) { break; } // // We only have time out for 95/98 // if (OS_W9X && (GetTickCount() - dwStartWaitTime >= HANGUP_TIMEOUT * 1000)) { CMTRACE(TEXT("DoRasHangup() Wait timed out")); break; } // // Try to dispatch message, however, some time the wait cursor is // changed back to arrow // MSG msg; while (PeekMessageU(&msg, NULL, 0, 0, PM_REMOVE)) { if (msg.message != WM_SETCURSOR) { TranslateMessage(&msg); DispatchMessageU(&msg); if (GetCursor() != hWaitCursor) { SetCursor(hWaitCursor); } } } Sleep(500); } if (dwRes == ERROR_INVALID_HANDLE) { dwRes = ERROR_SUCCESS; } else { CMTRACE1(TEXT("MyRasHangup() RasGetConnectStatus(), GLE=%u."), dwRes); } if (pfWaiting) { *pfWaiting = FALSE; } } CMTRACE(TEXT("DoRasHangup() completed")); return dwRes; } //+---------------------------------------------------------------------------- // // Function: MyRasHangup // // Synopsis: Simple wrapper for DoRasHangup, that takes pArgs as a param. // // Arguments: pArgs - Ptr to global Args struct // hRasConnection - The RAS device to hangup // hwndDlg - The main dlg to display "Disconnecting .. " msg // Only used if fWaitForComplete is TRUE // Optional, default = NULL // fWaitForComplete - Whether to wait for Hangup to complete on 95 // If set to TRUE, will wait until hRasConnection // is invalid. Optional, default = FALSE // // Returns: DWORD - ERROR_SUCCESS if success or error code // // History: nickball Implemented as wrapper 2/11/98 // //+---------------------------------------------------------------------------- DWORD MyRasHangup(ArgsStruct *pArgs, HRASCONN hRasConnection, HWND , BOOL fWaitForComplete) { CMTRACE(TEXT("MyRasHangup() calling DoRasHangup()")); return DoRasHangup(&pArgs->rlsRasLink, hRasConnection, NULL, fWaitForComplete, &pArgs->fIgnoreTimerRasMsg); } //+---------------------------------------------------------------------------- // // Function: HangupCM // // Synopsis: hangup both dial-up and tunnel connection, if exist // // Arguments: ArgsStruct *pArgs - // hwndDlg the main dlg to display "Disconnecting .. " msg // fWaitForComplete: Whether to wait for Hangup to complete on 95 // If set to TRUE, will wait until hRasConnection // is invalid. // // Returns: DWORD - // // History: fengsun Created Header 10/22/97 // fengsun Add fWaitForComplete 12/18/97 // //+---------------------------------------------------------------------------- DWORD HangupCM(ArgsStruct *pArgs, HWND hwndDlg, BOOL fWaitForComplete, BOOL fUpdateTable) { MYDBGASSERT(pArgs); MYDBGASSERT(hwndDlg); CMTRACE(TEXT("HangupCM()")); if (!pArgs) { CMTRACE(TEXT("HangupCM() invalid parameter.")); return (ERROR_INVALID_PARAMETER); } DWORD dwRes = ERROR_SUCCESS; // // If change password dialog is up tell it to go away // if (pArgs->hWndChangePassword) { CMTRACE(TEXT("HangupCM() Terminating ChangePassword dialog")); PostMessage(pArgs->hWndChangePassword, WM_COMMAND, IDCANCEL, 0); } // // If Callback number dialog is up tell it to go away too. // if (pArgs->hWndCallbackNumber) { CMTRACE(TEXT("HangupCM() Terminating CallbackNumber dialog")); PostMessage(pArgs->hWndCallbackNumber, WM_COMMAND, IDCANCEL, 0); } // // If Callback number dialog is up tell it to go away too. // if (pArgs->hWndRetryAuthentication) { CMTRACE(TEXT("HangupCM() Terminating RetryAuthentication dialog")); PostMessage(pArgs->hWndRetryAuthentication, WM_COMMAND, IDCANCEL, 0); } // // If table updates are desired set the entry to the disconnecting state // Note: In the case of redial, we don't want to modify the table state // even though we are hanging up because technically we are still connecting. // if (fUpdateTable) { UpdateTable(pArgs, CM_DISCONNECTING); } // // Check the RasLink pointer and hang up the device, tunnel first // #ifdef DEBUG if (!pArgs->rlsRasLink.pfnHangUp) { CMTRACE(TEXT("HangupCM() can't hang up.")); } #endif // // Show wait cursor before hanging up // HCURSOR hPrev; if (hwndDlg) { hPrev = SetCursor(LoadCursorU(NULL,IDC_WAIT)); ShowCursor(TRUE); } // // The assumption is that we have been connected, why else would we call // hangup. So release statistics handles, hooks, etc. // if (pArgs->pConnStatistics) { pArgs->pConnStatistics->Close(); } // // Hangup connections // if (pArgs->rlsRasLink.pfnHangUp && pArgs->hrcTunnelConn) { // // first, hangup tunnel connection // CMTRACE(TEXT("HangupCM() calling MyRasHangup() for tunnel connection")); dwRes = MyRasHangup(pArgs, pArgs->hrcTunnelConn, hwndDlg, fWaitForComplete); #ifdef DEBUG if (dwRes != ERROR_SUCCESS) { CMTRACE1(TEXT("MyRasHangup failed, GLE=%u."), GetLastError()); } #endif pArgs->hrcTunnelConn = NULL; } // // If we have a valid link and handle, hangup the modem // if (pArgs->rlsRasLink.pfnHangUp && pArgs->hrcRasConn) { CMTRACE(TEXT("HangupCM() calling MyRasHangup() for dial-up connection")); dwRes = MyRasHangup(pArgs, pArgs->hrcRasConn); } // Restore cursor if (hwndDlg) { ShowCursor(FALSE); SetCursor(hPrev); } pArgs->hrcRasConn = NULL; // // Update the Connection table if asked // if (fUpdateTable) { UpdateTable(pArgs, CM_DISCONNECTED); } return (dwRes); } //+---------------------------------------------------------------------------- // // Function: CleanupZapThread // // Synopsis: Simple helper to deal with signaling an event to stop Zap thread // and waiting for the thread to terminate. // // Arguments: HANDLE hEvent - The event handle // HANDLE hThread - Handle to the Zap thread. // // Returns: static void - Nothing // // History: nickball Created 3/5/98 // //+---------------------------------------------------------------------------- static void CleanupZapThread(HANDLE hEvent, HANDLE hThread) { MYDBGASSERT(hEvent); MYDBGASSERT(hThread); // // If we have an event, then it is assumed that have a Zap thread running // if (hEvent) { // // Signal termination to notify thread that we are done // BOOL bRes = SetEvent(hEvent); #ifdef DEBUG if (!bRes) { CMTRACE1(TEXT("CleanupZapThread() SetEvent() failed, GLE=%u."), GetLastError()); } #endif if (hThread) { // // Wait for thread to terminate, but pump messages in the mean time // BOOL bDone = FALSE; DWORD dwWaitCode; while (FALSE == bDone) { dwWaitCode = MsgWaitForMultipleObjects(1, &hThread, FALSE, MAX_OBJECT_WAIT, QS_ALLINPUT); switch(dwWaitCode) { // // Thread has terminated, or time is up, we're done here // case -1: CMTRACE1(TEXT("CleanupZapThread() MsgWaitForMultipleObjects returned an error GLE=%u."), GetLastError()); case WAIT_TIMEOUT: case WAIT_OBJECT_0: bDone = TRUE; break; // // If there is a message in the queue, process it // case WAIT_OBJECT_0+1: { MSG msg; while (PeekMessageU(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessageU(&msg); } break; } // // Unexpected, report, but continue // default: MYDBGASSERT(FALSE); } } // // We are done with the thread, close the handle // bRes = CloseHandle(hThread); #ifdef DEBUG if (!bRes) { CMTRACE1(TEXT("CleanupZapThread() CloseHandle(hThread) failed, GLE=%u."), GetLastError()); } #endif } // // Close our event handle // bRes = CloseHandle(hEvent); #ifdef DEBUG if (!bRes) { CMTRACE1(TEXT("CleanupZapThread() CloseHandle(hEvent) failed, GLE=%u."), GetLastError()); } #endif } } //+---------------------------------------------------------------------------- // // Function: OnConnectedCM // // Synopsis: Process WM_CONNECTED_CM which indicates that we are connected and // connect processing such as connect actions can begin // // Arguments: HWND hwndDlg - HWND of main dialog // ArgsStruct *pArgs - Ptr to global Args struct // // Returns: Nothing // // History: nickball Created 03/05/98 // //+---------------------------------------------------------------------------- void OnConnectedCM(HWND hwndDlg, ArgsStruct *pArgs) { HANDLE hEvent = NULL; HANDLE hThread = NULL; CActionList ConnectActList; CActionList AutoActList; // // Check to see if we are in a valid state to connect. if not just abort. // MYDBGASSERT(pArgs); if (pArgs->hrcRasConn == NULL && pArgs->hrcTunnelConn == NULL) { CMTRACE(TEXT("Bogus OnConnectCM msg received")); goto OnConnectedCMExit; } // // Set state to online // if (IsDialingTunnel(pArgs)) { // // This is a patch, it is only a patch - #187202 // UI should not be tied to RASENTRY type, but it is for now so we // have to make sure that it is set back to RASET_Internet once we // have our tunnel connection connected. // if (OS_NT5) { LPRASENTRY pRasEntry = MyRGEP(pArgs->pszRasPbk, pArgs->szServiceName, &pArgs->rlsRasLink); CMASSERTMSG(pRasEntry, TEXT("OnConnectedCM() - MyRGEP() failed.")); // // Set the type back and save the RASENTRY // if (pRasEntry) { ((LPRASENTRY_V500)pRasEntry)->dwType = RASET_Internet; if (pArgs->rlsRasLink.pfnSetEntryProperties) { DWORD dwTmp = pArgs->rlsRasLink.pfnSetEntryProperties(pArgs->pszRasPbk, pArgs->szServiceName, pRasEntry, pRasEntry->dwSize, NULL, 0); CMTRACE2(TEXT("OnConnectedCM() RasSetEntryProperties(*lpszEntry=%s) returns %u."), MYDBGSTR(pArgs->szServiceName), dwTmp); CMASSERTMSG(dwTmp == ERROR_SUCCESS, TEXT("RasSetEntryProperties for VPN failed")); } } CmFree(pRasEntry); } pArgs->psState = PS_TunnelOnline; } else { // // Set dial index back to primary number // pArgs->nDialIdx = 0; pArgs->psState = PS_Online; // // Make sure to update the stored username back to just the Username as RAS has saved the exact username // that we dialed with including realm info. // if (OS_NT5) { if (!pArgs->fUseTunneling || pArgs->fUseSameUserName) { if (0 != lstrcmpi(pArgs->szUserName, pArgs->pRasDialParams->szUserName)) { MYVERIFY(SaveUserInfo(pArgs, UD_ID_USERNAME, pArgs->szUserName)); } } else { if (0 != lstrcmpi(pArgs->szInetUserName, pArgs->pRasDialParams->szUserName)) { MYVERIFY(SaveUserInfo(pArgs, UD_ID_INET_USERNAME, pArgs->szInetUserName)); } } } } pArgs->dwStateStartTime = GetTickCount(); // pszMsg = GetDurMsg(g_hInst,pArgs->dwStateStartTime); // connect duration pArgs->nLastSecondsDisplay = (UINT) -1; // // added by byao: for PPTP connection // if (pArgs->fUseTunneling && pArgs->psState == PS_Online) { // // Now do the second dial: PPTP dialup // pArgs->psState = PS_TunnelDialing; pArgs->dwStateStartTime = GetTickCount(); pArgs->nLastSecondsDisplay = (UINT) -1; DWORD dwRes = DoTunnelDial(hwndDlg, pArgs); if (ERROR_SUCCESS != dwRes) { HangupCM(pArgs, hwndDlg); UpdateError(pArgs, dwRes); SetLastError(dwRes); } goto OnConnectedCMExit; } // // If this W95, then we need to Zap the RNA "Connected To" dialog // if (OS_W95) { // LPTSTR pszTmp = GetEntryName(pArgs, pArgs->pszRasPbk, pArgs->piniService); LPTSTR pszTmp = GetRasConnectoidName(pArgs, pArgs->piniService, FALSE); // // Create an event for signalling Zap thread to snuff itself out // hEvent = CreateEventU(NULL, TRUE, FALSE, NULL); if (hEvent) { hThread = ZapRNAConnectedTo(pszTmp, hEvent); } #ifdef DEBUG if (!hEvent) { CMTRACE1(TEXT("OnConnectedCM() CreateEvent failed, GLE=%u."), GetLastError()); } #endif CmFree(pszTmp); } pArgs->Log.Log(CONNECT_EVENT); // // If connection actions are enabled, update the list and run it // CMTRACE(TEXT("Connect Actions enabled: processsing Run List")); ConnectActList.Append(pArgs->piniService, c_pszCmSectionOnConnect); if (!ConnectActList.RunAccordType(hwndDlg, pArgs)) { // // Connect action failed // Run disconnect action // TCHAR szTmp[MAX_PATH]; MYVERIFY(GetModuleFileNameU(g_hInst, szTmp, MAX_PATH)); pArgs->Log.Log(DISCONNECT_EVENT, szTmp); // // Do not let disconnect action description overwrite the failure message // Save the status pane text and restore it after disconnect actions // 162942: Connect Action failed message is not displayed // TCHAR szFailedMsg[256] = TEXT(""); GetWindowTextU(GetDlgItem(hwndDlg, IDC_MAIN_STATUS_DISPLAY), szFailedMsg, sizeof(szFailedMsg)/sizeof(szFailedMsg[0])); CActionList DisconnectActList; DisconnectActList.Append(pArgs->piniService, c_pszCmSectionOnDisconnect); DisconnectActList.RunAccordType(hwndDlg, pArgs, FALSE); // fStatusMsgOnFailure = FALSE HangupCM(pArgs, hwndDlg); // // Restore the connect action failure message // if (szFailedMsg[0] != TEXT('\0')) { SetWindowTextU(GetDlgItem(hwndDlg, IDC_MAIN_STATUS_DISPLAY),szFailedMsg); } pArgs->dwExitCode = ERROR_CANCELLED; SetInteractive(hwndDlg,pArgs); goto OnConnectedCMExit; } // // Always run AutoApps if there are any. Used to only do this in the // non-autodial case, which was un-intuitive to our admin users. // AutoActList.Append(pArgs->piniService, c_pszCmSectionOnIntConnect); AutoActList.RunAutoApp(hwndDlg, pArgs); // // Connect to the connection monitor // if (SUCCEEDED(UpdateTable(pArgs, CM_CONNECTED))) { if (SUCCEEDED(ConnectMonitor(pArgs))) { EndMainDialog(hwndDlg, pArgs, 0); // TRUE); // // SUCCESS We're fully connected, update error code // as it may contain an interim value such as a // failed primary number dial. // pArgs->dwExitCode = ERROR_SUCCESS; } else { HangupCM(pArgs, hwndDlg); AppendStatusPane(hwndDlg,IDMSG_CMMON_LAUNCH_FAIL); SetInteractive(hwndDlg,pArgs); goto OnConnectedCMExit; } } // // Update changed password if needed // if (pArgs->fChangedPassword && pArgs->fRememberMainPassword) { // // Note: fRememberMainPassword should never be set in the // WinLogon case. Complain if we have WinLogon specific data. // MYDBGASSERT(!pArgs->lpRasNoUser); MYDBGASSERT(!pArgs->lpEapLogonInfo); // // If the password has changed, then update storage // CmDecodePassword(pArgs->szPassword); // convert to plain text 1st SaveUserInfo(pArgs, UD_ID_PASSWORD, (PVOID)pArgs->szPassword); if (pArgs->fUseSameUserName) { SaveUserInfo(pArgs, UD_ID_INET_PASSWORD, (PVOID)pArgs->szPassword); } CmEncodePassword(pArgs->szPassword); // restore internal encoding if (pArgs->fUseSameUserName) { // // Just in case somebody doesn't reload it. Note: Encoded above. // lstrcpyU(pArgs->szInetPassword, pArgs->szPassword); } pArgs->fChangedPassword = FALSE; } OnConnectedCMExit: if (hEvent) { MYDBGASSERT(OS_W9X); CleanupZapThread(hEvent, hThread); } return; } //+---------------------------------------------------------------------------- // // Function: SetTcpWindowSizeOnWin2k // // Synopsis: This function is basically a wrapper to load the RasSetEntryTcpWindowSize // API (which was QFE-ed and shipped in SP3 for Win2k) and call it. // It should fail gracefully if the API is not present. // // Arguments: HMODULE hInstRas - module handle for Rasapi32.dll // LPCTSTR pszConnectoid - name of the connectoid to set the window size for // LPCTSTR pszPhonebook - phonebook that the connectoid lives in // DWORD dwTcpWindowSize - size to set, note that calling with 0 // sets it to the system default // // Returns: DWORD - win32 error code or ERROR_SUCCESS if successful // // History: quintinb Created 02/14/2001 // //+---------------------------------------------------------------------------- DWORD SetTcpWindowSizeOnWin2k(HMODULE hInstRas, LPCTSTR pszConnectoid, LPCTSTR pszPhonebook, DWORD dwTcpWindowSize) { // // Check inputs, note that pszPhonebook could be NULL // if ((NULL == hInstRas) || (NULL == pszConnectoid) || (TEXT('\0') == pszConnectoid[0])) { CMASSERTMSG(FALSE, TEXT("SetTcpWindowSizeOnWin2k -- Invalid arguments passed.")); return ERROR_BAD_ARGUMENTS; } // // Check to make sure we are only calling this on Win2k // if ((FALSE == OS_NT5) || OS_NT51) { CMASSERTMSG(FALSE, TEXT("SetTcpWindowSizeOnWin2k -- This function should only be called on Win2k.")); return -1; } // // See if we can load the new RAS function to set the Window size // LPCSTR c_pszDwSetEntryPropertiesPrivate = "DwSetEntryPropertiesPrivate"; typedef DWORD (WINAPI *pfnDwSetEntryPropertiesPrivateSpec)(IN LPCWSTR, IN LPCWSTR, IN DWORD, IN PVOID); DWORD dwReturn; pfnDwSetEntryPropertiesPrivateSpec pfnDwSetEntryPropertiesPrivate = (pfnDwSetEntryPropertiesPrivateSpec)GetProcAddress(hInstRas, c_pszDwSetEntryPropertiesPrivate); if (pfnDwSetEntryPropertiesPrivate) { RASENTRY_EX_0 PrivateRasEntryExtension; PrivateRasEntryExtension.dwTcpWindowSize = dwTcpWindowSize; dwReturn = (pfnDwSetEntryPropertiesPrivate)(pszConnectoid, pszPhonebook, 0, &PrivateRasEntryExtension); // 0 = struct version num MYDBGASSERT(ERROR_SUCCESS == dwReturn); } else { dwReturn = GetLastError(); } return dwReturn; } //+---------------------------------------------------------------------------- // // Function: DoRasDial // // Synopsis: Call RasDial to dial the PPP connection // // Arguments: HWND hwndDlg - Main signon window // ArgsStruct *pArgs - // DWORD dwEntry - The index in pArgs->aDialInfo // // Returns: DWORD - // ERROR_SUCCESS if success // ERROR_NOT_ENOUGH_MEMORY // E_UNEXPECTED, unexpected error, such as tunnel address not found // Otherwise, RAS error // // History: fengsun Created Header 3/6/98 // //+---------------------------------------------------------------------------- DWORD DoRasDial(HWND hwndDlg, ArgsStruct *pArgs, DWORD dwEntry) { LPRASENTRY preRasEntry = NULL; LPRASSUBENTRY rgRasSubEntry = NULL; LPRASEAPUSERIDENTITY lpRasEapUserIdentity = NULL; DWORD dwSubEntryCount; LPTSTR pszUsername; LPTSTR pszPassword; LPTSTR pszDomain = NULL; LPTSTR pszRasPbk; LPTSTR pszTmp; CIni *piniService = NULL; DWORD dwRes = ERROR_SUCCESS; // the return value of this function DWORD dwTmp; LPBYTE pbEapAuthData = NULL; // Ptr to Eap Data DWORD dwEapAuthDataSize = 0; // The size of the EAP blob if any MYDBGASSERT(pArgs->hrcRasConn == NULL); MYDBGASSERT(!pArgs->IsDirectConnect()); pArgs->hrcRasConn = NULL; if (!pArgs->aDialInfo[dwEntry].szDialablePhoneNumber[0]) { CMASSERTMSG(FALSE, TEXT("DoRasDial() szDialablePhoneNumber[0] is empty.")); return ERROR_BAD_PHONE_NUMBER; } // // set pArgs->fUseTunneling accordingly every time DoRasDial() is called // since we can switch from phonenumber0 to phonenumber1 and vice versa. // pArgs->fUseTunneling = UseTunneling(pArgs, dwEntry); // // we need to work with the correct service file(the top-level service // or a referenced service). // // if (!(piniService = GetAppropriateIniService(pArgs, dwEntry))) { return ERROR_NOT_ENOUGH_MEMORY; } // // If it's NT and we're tunneling, we create the connectoid in a hidden ras pbk, not the // rasphone.pbk in the system. // if (OS_NT && pArgs->fUseTunneling) { if (!pArgs->pszRasHiddenPbk) { pArgs->pszRasHiddenPbk = CreateRasPrivatePbk(pArgs); } pszRasPbk = pArgs->pszRasHiddenPbk; } else { pszRasPbk = pArgs->pszRasPbk; } // // Setup dial params // if (!pArgs->pRasDialParams) { pArgs->pRasDialParams = AllocateAndInitRasDialParams(); if (!pArgs->pRasDialParams) { CMTRACE(TEXT("DoRasDial: failed to alloc a ras dial params")); return ERROR_NOT_ENOUGH_MEMORY; } } else { InitRasDialParams(pArgs->pRasDialParams); } // // Get the connectoid name. // LPTSTR pszConnectoid = GetRasConnectoidName(pArgs, pArgs->piniService, FALSE); if (!pszConnectoid) { return ERROR_NOT_ENOUGH_MEMORY; } lstrcpynU(pArgs->pRasDialParams->szEntryName, pszConnectoid, sizeof(pArgs->pRasDialParams->szEntryName)/sizeof(TCHAR)); CmFree(pszConnectoid); // // Generate the default connectoid // preRasEntry = CreateRASEntryStruct(pArgs, pArgs->aDialInfo[dwEntry].szDUN, piniService, FALSE, pszRasPbk, &pbEapAuthData, &dwEapAuthDataSize); if (!preRasEntry) { dwRes = GetLastError(); goto exit; } // // Force update of the phone number to make sure that we pick up any manual // changes in country, etc. // CopyPhone(pArgs, preRasEntry, dwEntry); // // Handle NT specifics for Idle Disconnect and IDSN // if (OS_NT || OS_MIL) { // // set NT idle disconnect // if (OS_NT) { SetNtIdleDisconnectInRasEntry(pArgs, preRasEntry); } else { MYVERIFY(DisableSystemIdleDisconnect(preRasEntry)); } // // if we're using isdn and we want to dial all channels/on demand, // set isdn dial mode // if (pArgs->dwIsdnDialMode != CM_ISDN_MODE_SINGLECHANNEL && !lstrcmpiU(pArgs->szDeviceType, RASDT_Isdn)) { MYVERIFY(SetIsdnDualChannelEntries(pArgs, preRasEntry, &rgRasSubEntry, &dwSubEntryCount)); } else { // // Delete any additional sub entries since we only need one // if (pArgs->rlsRasLink.pfnDeleteSubEntry) // available on NT5 & Millennium currently { DWORD dwSubEntryIndex = (OS_MIL ? 1 : 2); // NT & Millennium dual-channel differences DWORD dwReturn = pArgs->rlsRasLink.pfnDeleteSubEntry(pszRasPbk, pArgs->pRasDialParams->szEntryName, dwSubEntryIndex); CMTRACE1(TEXT("DoRasDial -- Called RasDeleteSubEntry to delete a second sub entry if it exists, dwReturn=%d"), dwReturn); } } } else if (OS_W95) { // // fix another Win95 RAS bug -- byao, 8/16/97 // The Before and After terminal window options will be switched each // time you call RasSetEntryProperties // This is fixed in Memphis, so it's only in Win95 Golden and OSR2 // BOOL fTerminalAfterDial, fTerminalBeforeDial; fTerminalBeforeDial = (BOOL) (preRasEntry->dwfOptions & RASEO_TerminalBeforeDial); fTerminalAfterDial = (BOOL) (preRasEntry->dwfOptions & RASEO_TerminalAfterDial); // // switch them // if (fTerminalBeforeDial) { preRasEntry->dwfOptions |= RASEO_TerminalAfterDial; } else { preRasEntry->dwfOptions &= ~RASEO_TerminalAfterDial; } if (fTerminalAfterDial) { preRasEntry->dwfOptions |= RASEO_TerminalBeforeDial; } else { preRasEntry->dwfOptions &= ~RASEO_TerminalBeforeDial; } } if (pArgs->rlsRasLink.pfnSetEntryProperties) { #ifdef DEBUG LPRASENTRY_V500 lpRasEntry50; if (OS_NT5) { lpRasEntry50 = (LPRASENTRY_V500) preRasEntry; } #endif // // use 1 on Millennium to signify that we want to use the modem cpl settings // for the modem speaker such instead of the cached copy that DUN keeps. // Note we only do this for a dialup connection and not a tunnel since there // is no modem speaker to worry about. See Millennium bug 127371. // LPBYTE lpDeviceInfo = OS_MIL ? (LPBYTE)1 : NULL; DWORD dwResDbg = pArgs->rlsRasLink.pfnSetEntryProperties(pszRasPbk, pArgs->pRasDialParams->szEntryName, preRasEntry, preRasEntry->dwSize, lpDeviceInfo, 0); CMTRACE2(TEXT("DoRasDial() RasSetEntryProperties(*pszPhoneBook=%s) returns %u."), MYDBGSTR(pArgs->pRasDialParams->szEntryName), dwResDbg); CMASSERTMSG(dwResDbg == ERROR_SUCCESS, TEXT("RasSetEntryProperties failed")); // // set the subentries for isdn dual channel/dial on demand // if (pArgs->dwIsdnDialMode != CM_ISDN_MODE_SINGLECHANNEL && rgRasSubEntry && pArgs->rlsRasLink.pfnSetSubEntryProperties) { UINT i; for (i=0; i< dwSubEntryCount; i++) { #ifdef DEBUG dwResDbg = #endif pArgs->rlsRasLink.pfnSetSubEntryProperties(pszRasPbk, pArgs->pRasDialParams->szEntryName, i+1, &rgRasSubEntry[i], rgRasSubEntry[i].dwSize, NULL, 0); CMTRACE2(TEXT("DoRasDial: RasSetSubEntryProps(index=%u) returned %u"), i+1, dwResDbg); CMASSERTMSG(!dwResDbg, TEXT("RasSetSubEntryProperties failed")); } CmFree(rgRasSubEntry); } } // // Set the TCP Window size -- the NTT DoCoMo fix for Win2k. The Win2k version of this fix // must be written through a private RAS API that must be called after the phonebook entry // exists ie. after we call RasSetEntryProperties ... otherwise it won't work on the first // dial. // if (OS_NT5 && !OS_NT51) { // // Figure out the DUN setting name to use and then build up TCP/IP&DunName. // LPTSTR pszDunSetting = GetDunSettingName(pArgs, dwEntry, FALSE); LPTSTR pszSection = CmStrCpyAlloc(c_pszCmSectionDunTcpIp); pszSection = CmStrCatAlloc(&pszSection, TEXT("&")); if (pszDunSetting && pszSection) { pszSection = CmStrCatAlloc(&pszSection, pszDunSetting); if (pszSection) { DWORD dwTcpWindowSize = piniService->GPPI(pszSection, c_pszCmEntryDunTcpIpTcpWindowSize, 0); (void)SetTcpWindowSizeOnWin2k(pArgs->rlsRasLink.hInstRas, pArgs->szServiceName, pszRasPbk, dwTcpWindowSize); } else { CMASSERTMSG(FALSE, TEXT("DoRasDial -- unable to allocate section name for setting TcpWindowSize")); } } else { CMASSERTMSG(FALSE, TEXT("DoRasDial -- unable to allocate section name or dun setting name for setting TcpWindowSize")); } CmFree (pszDunSetting); CmFree (pszSection); } // // On NT5, check for EAP configuration and update the connectoid accordingly. // if (OS_NT5) { if (pbEapAuthData && dwEapAuthDataSize && pArgs->rlsRasLink.pfnSetCustomAuthData) { dwTmp = pArgs->rlsRasLink.pfnSetCustomAuthData(pszRasPbk, pArgs->pRasDialParams->szEntryName, pbEapAuthData, dwEapAuthDataSize); CMTRACE1(TEXT("DoRasDial() - SetCustomAuthData returns %u"), dwTmp); if (ERROR_SUCCESS != dwTmp) { dwRes = dwTmp; goto exit; } } } // // Prepare Phone Number // lstrcpynU(pArgs->pRasDialParams->szPhoneNumber, pArgs->aDialInfo[dwEntry].szDialablePhoneNumber, sizeof(pArgs->pRasDialParams->szPhoneNumber)/sizeof(TCHAR)); // // Prepare user info // // #165775 - RADIUS/CHAP authentication requires that we omit the // user specified domain from the dial params and pre-pend it to // the user name instead when doing same-name logon. - nickball // if (!pArgs->fUseTunneling || pArgs->fUseSameUserName) { pszUsername = pArgs->szUserName; pszPassword = pArgs->szPassword; pszDomain = pArgs->szDomain; } else { // // if there's no username or password, we need to ask the user for it. // if (!*pArgs->szInetUserName && !pArgs->fHideInetUsername && !pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryUserNameOptional) || !*pArgs->szInetPassword && !pArgs->fHideInetPassword && !pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryPwdOptional)) { // // We need to collect data from user, determine the dlg template ID // UINT uiTemplateID = IDD_INTERNET_SIGNIN; if (pArgs->fHideInetUsername) { uiTemplateID = IDD_INTERNET_SIGNIN_NO_UID; } else if (pArgs->fHideInetPassword) { uiTemplateID = IDD_INTERNET_SIGNIN_NO_PWD; } // // Now load the dialog // CInetSignInDlg SignInDlg(pArgs); if (IDCANCEL == SignInDlg.DoDialogBox(g_hInst, uiTemplateID, hwndDlg)) { dwRes = ERROR_CANCELLED; goto exit; } } pszUsername = pArgs->szInetUserName; pszPassword = pArgs->szInetPassword; } // // Apply suffix, prefix, to username as necessary // pszTmp = ApplyPrefixSuffixToBufferAlloc(pArgs, piniService, pszUsername); MYDBGASSERT(pszTmp); if (pszTmp) { // // Apply domain to username as necessary. Note: Reassigns pszUsername // pszUsername = ApplyDomainPrependToBufferAlloc(pArgs, piniService, pszTmp, (pArgs->aDialInfo[dwEntry].szDUN)); MYDBGASSERT(pszUsername); if (pszUsername) { lstrcpynU(pArgs->pRasDialParams->szUserName, pszUsername, sizeof(pArgs->pRasDialParams->szUserName)/sizeof(TCHAR)); } CmFree(pszUsername); CmFree(pszTmp); } pszUsername = NULL; pszTmp = NULL; // // Update RasDialPArams with domain info if we have any // if (pszDomain) { lstrcpyU(pArgs->pRasDialParams->szDomain, pszDomain); } // // Prepare the password // CmDecodePassword(pszPassword); // // Convert password: all upper case, all lower case, or no conversion // ApplyPasswordHandlingToBuffer(pArgs, pszPassword); // // Encode password to minimize plain text exposure time, especially crucial // when running things like connect actions, which can both take time and // potentially crash. // CmEncodePassword(pszPassword); if (pArgs->rlsRasLink.pfnDial) { LPTSTR pszDunSetting = GetDunSettingName(pArgs, dwEntry, FALSE); LPTSTR pszPhoneBook = GetCMSforPhoneBook(pArgs, dwEntry); pArgs->Log.Log(PREDIAL_EVENT, pArgs->pRasDialParams->szUserName, pArgs->pRasDialParams->szDomain, SAFE_LOG_ARG(pszPhoneBook), SAFE_LOG_ARG(pszDunSetting), pArgs->tlsTapiLink.szDeviceName, pArgs->aDialInfo[dwEntry].szDialablePhoneNumber); CmFree(pszDunSetting); CmFree(pszPhoneBook); // // Run pre-dial connect action before calling RasDial // CActionList PreDialActList; PreDialActList.Append(pArgs->piniService, c_pszCmSectionPreDial); if (!PreDialActList.RunAccordType(hwndDlg, pArgs)) { // // Some pre-tunnel connect action failed // dwRes = ERROR_INVALID_DLL; // Only used for failed CA } else { // // Set state and tick counters. // pArgs->psState = PS_Dialing; pArgs->dwStateStartTime = GetTickCount(); pArgs->nLastSecondsDisplay = (UINT) -1; // // Record the initial Dial-Up Adapter Statistic info // open the registry key for the perfmon data // if (pArgs->pConnStatistics) { pArgs->pConnStatistics->InitStatistics(); } if (OS_NT) { BOOL fUsePausedStates = TRUE; BOOL fUseCustomScripting = !!(preRasEntry->dwfOptions & RASEO_CustomScript); // OS_NT51 (whistler+) only if (OS_NT4) { // // If a script is specified, then explcitly don't handle // pause states. This is because we can't handle the script // pause state. On W2K, RAS is smart enough not to send us // the scripting pause state because we have the terminal // option turned off. // if (preRasEntry->szScript[0] != TEXT('\0')) { fUsePausedStates = FALSE; } } dwRes = SetRasDialExtensions(pArgs, fUsePausedStates, fUseCustomScripting); if (dwRes != ERROR_SUCCESS) { goto exit; } // // On NT5, we may be getting credentials via EAP // if (OS_NT5 && ((LPRASENTRY_V500)preRasEntry)->dwCustomAuthKey) { // // We're using EAP, get credentials from EAP through RAS // dwRes = GetEapUserId(pArgs, hwndDlg, pszRasPbk, pbEapAuthData, dwEapAuthDataSize, ((LPRASENTRY_V500)preRasEntry)->dwCustomAuthKey, &lpRasEapUserIdentity); if (ERROR_SUCCESS != dwRes) { goto exit; } } } CMTRACE1(TEXT("DoRasDial: pArgs->pRasDialParams->szUserName is %s"), pArgs->pRasDialParams->szUserName); CMTRACE1(TEXT("DoRasDial: pArgs->pRasDialParams->szDomain is %s"), pArgs->pRasDialParams->szDomain); CMTRACE1(TEXT("DoRasDial: pArgs->pRasDialParams->szPhoneNumber is %s"), pArgs->pRasDialParams->szPhoneNumber); // // Decode the password, and fill dial params, then re-encode both the pArgs // version of the password and the dial params copy. // CmDecodePassword(pszPassword); lstrcpynU(pArgs->pRasDialParams->szPassword, pszPassword, sizeof(pArgs->pRasDialParams->szPassword)/sizeof(TCHAR)); // // Write the RasDialParams if necessary. // We must keep this, even though RasSetEntryDialParams() is expensive. Inverse uses the // information stored in the DialParams structure. However, since this can cause problems // with EAP (overwriting the saved PIN for instance) we will make the storing of the // credential information configurable by a CMS flag. Specifically, the WriteRasDialParams // flag in the [Connection Manager] section. If the flag is 1, then we will write the // RasDialParams and otherwise we won't. Note that the flag defaults to 0. // Please see bug 399976 for reference. // if (piniService->GPPI(c_pszCmSection, c_pszCmEntryWriteDialParams)) { // // Note that since we throw the connectoid away if we are on NT and // doing a double dial, there is no point in making an expensive set // dial params call on it. // if ((!pArgs->fUseTunneling && pArgs->fRememberMainPassword) || (pArgs->fUseTunneling && pArgs->fRememberInetPassword && OS_W9X)) { DWORD dwResDbg = pArgs->rlsRasLink.pfnSetEntryDialParams(pszRasPbk, pArgs->pRasDialParams, FALSE); CMTRACE1(TEXT("DoRasDial() SetEntryDialParams returns %u."), dwResDbg); } else { // // Forget the password, note that the DialParams contain the password but we set the // fRemovePassword flag to TRUE so the password will be removed anyway. // DWORD dwResDbg = pArgs->rlsRasLink.pfnSetEntryDialParams(pszRasPbk, pArgs->pRasDialParams, TRUE); CMTRACE1(TEXT("DoRasDial() SetEntryDialParams returns %u."), dwResDbg); } } // // Do the dial (PPP) // if (OS_NT) { lstrcpyU(pArgs->pRasDialParams->szCallbackNumber, TEXT("*")); } // // check to ensure we're not already in a Cancel operation // LONG lInConnectOrCancel = InterlockedExchange(&(pArgs->lInConnectOrCancel), IN_CONNECT_OR_CANCEL); CMASSERTMSG(((NOT_IN_CONNECT_OR_CANCEL == lInConnectOrCancel) || (IN_CONNECT_OR_CANCEL == lInConnectOrCancel)), TEXT("DoRasDial - synch variable has unexpected value!")); if (NOT_IN_CONNECT_OR_CANCEL == lInConnectOrCancel) { dwRes = pArgs->rlsRasLink.pfnDial(pArgs->pRasDialExtensions, pszRasPbk, pArgs->pRasDialParams, GetRasCallBackType(), GetRasCallBack(pArgs), &pArgs->hrcRasConn); } else { // this is a rare stress case - deliberately did not set dwRes to error value. CMTRACE(TEXT("DoRasDial() did not dial, we are already in a Cancel operation")); } (void) InterlockedExchange(&(pArgs->lInConnectOrCancel), NOT_IN_CONNECT_OR_CANCEL); CmEncodePassword(pArgs->pRasDialParams->szPassword); CmEncodePassword(pszPassword); CMTRACE1(TEXT("DoRasDial() RasDial() returns %u."), dwRes); if (dwRes != ERROR_SUCCESS) { pArgs->hrcRasConn = NULL; goto exit; } } } exit: if (lpRasEapUserIdentity) { MYDBGASSERT(OS_NT5); // NO EAP down-level // // A RasEapUserIdentity struct was allocated, free it via the // appropriate free mechanism. In the WinLogon case we will always // perform the allocation, otherwise we have to go through RAS API. // if (pArgs->lpEapLogonInfo) { CmFree(lpRasEapUserIdentity); } else { if (pArgs->rlsRasLink.pfnFreeEapUserIdentity) { pArgs->rlsRasLink.pfnFreeEapUserIdentity(lpRasEapUserIdentity); } } } CmFree(pbEapAuthData); CmFree(preRasEntry); delete piniService; return dwRes; } //+--------------------------------------------------------------------------- // // Function: DoTunnelDial // // Synopsis: call RasDial to dial up to the tunnel server // // Arguments: hwndDlg [dlg window handle] // pargs pointer to ArgValue structure // // Returns: DWORD - // ERROR_SUCCESS if success // ERROR_NOT_ENOUGH_MEMORY // E_UNEXPECTED, unexpected error, such as phone entry not found // Otherwise, RAS error // // History: byao Created 3/1/97 // fengsun change return type to DWORD 3/6/98 // //---------------------------------------------------------------------------- DWORD DoTunnelDial(IN HWND hwndDlg, IN ArgsStruct *pArgs) { LPRASENTRY preRasEntry = NULL; LPRASEAPUSERIDENTITY lpRasEapUserIdentity = NULL; LPTSTR pszVpnSetting = NULL; LPBYTE pbEapAuthData = NULL; // Ptr to Eap Data DWORD dwEapAuthDataSize = 0; // The size of the EAP blob if any LPTSTR pszPassword = pArgs->szPassword; DWORD dwRes = (DWORD)E_UNEXPECTED; DWORD dwTmp; MYDBGASSERT(pArgs->hrcTunnelConn == NULL); pArgs->hrcTunnelConn = NULL; // // What's the tunnel end point? Do this now so that the UI can be updated // properly if lana wait or pre-tunnel actions are time consuming. // LPTSTR pszTunnelIP = pArgs->piniBothNonFav->GPPS(c_pszCmSection, c_pszCmEntryTunnelAddress); if (pszTunnelIP) { if (lstrlenU(pszTunnelIP) > RAS_MaxPhoneNumber) { pszTunnelIP[0] = TEXT('\0'); } pArgs->SetPrimaryTunnel(pszTunnelIP); CmFree(pszTunnelIP); } // // See if tunnel server was specified // if (!(pArgs->GetTunnelAddress()[0])) { CMASSERTMSG(FALSE, TEXT("DoTunnelDial() TunnelAddress is invalid.")); return ERROR_BAD_ADDRESS_SPECIFIED; } CMTRACE1(TEXT("DoTunnelDial() - TunnelAddress is %s"), pArgs->GetTunnelAddress()); // // Caution should be used when changing this if statement. We want this to happen both for direct connect // and for double dial connections. You can still get into the LANA situation with two CM // connections dialed independently (one to the internet and the other a tunnel), doing the lana // wait for direct connections prevents the lana registration problem from occuring in this situation. // Note that the Lana wait isn't necessary on Win98 SE or Win98 Millennium because the DUN bug // is fixed. Thus we have reversed the default and will only do the LANA wait if the reg key exists // and specifies that the wait should be performed. // if (OS_W9X) { // // Sets us up to wait for Vredir to register LANA for connection to internet // Note: Returns FALSE if the user hits cancel while we are waiting. In this // event, we should not continue the tunnel dial. // if (FALSE == LanaWait(pArgs, hwndDlg)) { return ERROR_SUCCESS; } } LPTSTR pszDunSetting = GetDunSettingName(pArgs, -1, TRUE); pArgs->Log.Log(PRETUNNEL_EVENT, pArgs->szUserName, pArgs->szDomain, SAFE_LOG_ARG(pszDunSetting), pArgs->tlsTapiLink.szDeviceName, pArgs->GetTunnelAddress()); CmFree(pszDunSetting); CActionList PreTunnelActList; if (PreTunnelActList.Append(pArgs->piniService, c_pszCmSectionPreTunnel)) { CMTRACE(TEXT("DoTunnelDial() - Running Pre-Tunnel actions")); if (!PreTunnelActList.RunAccordType(hwndDlg, pArgs)) { // // Some pre-tunnel connect action failed // dwRes = ERROR_INVALID_DLL; // Only used for failed CA goto exit; } // // Now that pre-tunnel actions have run, what's the tunnel end point? // We perform this read again here in the event that the pre-tunnel // action modified the tunnel address. Note: This is an exception to // the rule that the .CMS should not be modified on the client side, // especially by 3rd parties. // // REVIEW: It probably isn't necessary to re-read this with the new VPN tab. However, some people might still // be using the connect action solution that ITG gave out and we want to be careful not to break them if // we haven't already. Thus we will continue to re-read this for Whistler but we should remove it afterwards. // quintinb 11-01-00 pszTunnelIP = pArgs->piniBothNonFav->GPPS(c_pszCmSection, c_pszCmEntryTunnelAddress); if (pszTunnelIP) { if (lstrlenU(pszTunnelIP) > RAS_MaxPhoneNumber) { pszTunnelIP[0] = TEXT('\0'); } pArgs->SetPrimaryTunnel(pszTunnelIP); CmFree(pszTunnelIP); } // // See if tunnel server was specified // if (!(pArgs->GetTunnelAddress()[0])) { CMASSERTMSG(FALSE, TEXT("DoTunnelDial() TunnelAddress is invalid.")); dwRes = (DWORD)ERROR_BAD_ADDRESS_SPECIFIED; goto exit; } CMTRACE1(TEXT("DoTunnelDial() - TunnelAddress is %s"), pArgs->GetTunnelAddress()); } // // Setup dial params // if (!pArgs->pRasDialParams) { pArgs->pRasDialParams = AllocateAndInitRasDialParams(); if (!pArgs->pRasDialParams) { CMTRACE(TEXT("DoTunnelDial: failed to alloc a ras dial params")); dwRes = ERROR_NOT_ENOUGH_MEMORY; goto exit; } } else { InitRasDialParams(pArgs->pRasDialParams); } // // Get the connectoid name // LPTSTR pszConnectoid; pszConnectoid = GetRasConnectoidName(pArgs, pArgs->piniService, TRUE); if (!pszConnectoid) { dwRes = (DWORD)ERROR_NOT_ENOUGH_MEMORY; goto exit; } lstrcpyU(pArgs->pRasDialParams->szEntryName, pszConnectoid); CmFree(pszConnectoid); // // We'll create the RAS connectoid if the RAS connectoid doesn't exist. // NOTE: Tunnel settings should always be taken from the top-level CMS. // so use it when creating the connectoid. // pszVpnSetting = pArgs->piniBothNonFav->GPPS(c_pszCmSection, c_pszCmEntryTunnelDun, TEXT("")); preRasEntry = CreateRASEntryStruct(pArgs, (pszVpnSetting ? pszVpnSetting : TEXT("")), pArgs->piniService, TRUE, pArgs->pszRasPbk, &pbEapAuthData, &dwEapAuthDataSize); CmFree(pszVpnSetting); if (!preRasEntry) { dwRes = GetLastError(); goto exit; } // // If this is Millennium we need to disable Idle disconnect so that it doesn't // fight with ours. // if (OS_MIL) { MYVERIFY(DisableSystemIdleDisconnect(preRasEntry)); } // // We need to delete a second sub entry if it exists. See 406637 for details // if (pArgs->rlsRasLink.pfnDeleteSubEntry) // available on NT5 & Millennium currently { DWORD dwReturn = pArgs->rlsRasLink.pfnDeleteSubEntry(pArgs->pszRasPbk, pArgs->pRasDialParams->szEntryName, (OS_MIL ? 1 : 2)); // see comment in DoRasDial CMTRACE1(TEXT("DoTunnelDial -- Called RasDeleteSubEntry to delete a second sub entry if it exists, dwReturn=%d"), dwReturn); } // // On NT5, we have to set the connection type to VPN instead of Internet // if (OS_NT5) { MYDBGASSERT(preRasEntry->dwSize >= sizeof(RASENTRY_V500)); ((LPRASENTRY_V500)preRasEntry)->dwType = RASET_Vpn; ((LPRASENTRY_V500)preRasEntry)->szDeviceName[0] = TEXT('\0'); // let RAS pickup the tunnel device } if (pArgs->rlsRasLink.pfnSetEntryProperties) { #ifdef DEBUG LPRASENTRY_V500 lpRasEntry50; if (OS_NT5) { lpRasEntry50 = (LPRASENTRY_V500) preRasEntry; } #endif dwRes = pArgs->rlsRasLink.pfnSetEntryProperties(pArgs->pszRasPbk, pArgs->pRasDialParams->szEntryName, preRasEntry, preRasEntry->dwSize, NULL, 0); CMTRACE2(TEXT("DoTunnelDial() RasSetEntryProperties(*lpszEntry=%s) returns %u."), MYDBGSTR(pArgs->pRasDialParams->szEntryName,), dwRes); CMASSERTMSG(dwRes == ERROR_SUCCESS, TEXT("RasSetEntryProperties for VPN failed")); } // // Set the TCP Window size -- the NTT DoCoMo fix for Win2k. The Win2k version of this fix // must be written through a private RAS API that must be called after the phonebook entry // exists ie. after we call RasSetEntryProperties ... otherwise it won't work on the first // dial. // if (OS_NT5 && !OS_NT51) { // // Figure out the DUN setting name to use and then build up TCP/IP&DunName. // LPTSTR pszDunSetting = GetDunSettingName(pArgs, -1, TRUE); LPTSTR pszSection = CmStrCpyAlloc(c_pszCmSectionDunTcpIp); pszSection = CmStrCatAlloc(&pszSection, TEXT("&")); if (pszDunSetting && pszSection) { pszSection = CmStrCatAlloc(&pszSection, pszDunSetting); if (pszSection) { DWORD dwTcpWindowSize = pArgs->piniService->GPPI(pszSection, c_pszCmEntryDunTcpIpTcpWindowSize, 0); (void)SetTcpWindowSizeOnWin2k(pArgs->rlsRasLink.hInstRas, pArgs->szServiceName, pArgs->pszRasPbk, dwTcpWindowSize); } else { CMASSERTMSG(FALSE, TEXT("DoTunnelDial -- unable to allocate section name for setting TcpWindowSize")); } } else { CMASSERTMSG(FALSE, TEXT("DoTunnelDial -- unable to allocate section name or dun setting name for setting TcpWindowSize")); } CmFree (pszDunSetting); CmFree (pszSection); } // // On NT5, check for EAP configuration and update the connectoid accordingly. // if (OS_NT5) { if (pbEapAuthData && dwEapAuthDataSize && pArgs->rlsRasLink.pfnSetCustomAuthData) { dwTmp = pArgs->rlsRasLink.pfnSetCustomAuthData(pArgs->pszRasPbk, pArgs->pRasDialParams->szEntryName, pbEapAuthData, dwEapAuthDataSize); if (ERROR_SUCCESS != dwTmp) { CMTRACE(TEXT("DoTunnelDial() - SetCustomAuthData failed")); dwRes = dwTmp; goto exit; } } } // // Phone Number for PPTP is the DNS name of IP addr of PPTP server // lstrcpynU(pArgs->pRasDialParams->szPhoneNumber,pArgs->GetTunnelAddress(), sizeof(pArgs->pRasDialParams->szPhoneNumber)); // // Prepare User Name and Domain // lstrcpyU(pArgs->pRasDialParams->szUserName, pArgs->szUserName); lstrcpyU(pArgs->pRasDialParams->szDomain, pArgs->szDomain); // // Prepare the password // CmDecodePassword(pszPassword); // // Convert password: all upper case, all lower case, or no conversion // ApplyPasswordHandlingToBuffer(pArgs, pszPassword); // // Re-encode password while we take care of other business. // CmEncodePassword(pszPassword); if (pArgs->rlsRasLink.pfnDial) { if (pArgs->IsDirectConnect()) { // // Record the initial Dial-Up Adapter Statistic info. // if (pArgs->pConnStatistics) { pArgs->pConnStatistics->InitStatistics(); } } if (OS_NT) { MYDBGASSERT(TEXT('\0') == preRasEntry->szScript[0]); // we should never have a script on a tunnel connection dwRes = SetRasDialExtensions(pArgs, TRUE, FALSE); // TRUE == fUsePausedStates, FALSE == fEnableCustomScripting if (dwRes != ERROR_SUCCESS) { goto exit; } // // On NT5, we may be getting credentials via EAP // if (OS_NT5 && ((LPRASENTRY_V500)preRasEntry)->dwCustomAuthKey) { // // We're using EAP, get credentials from EAP through RAS // dwRes = GetEapUserId(pArgs, hwndDlg, pArgs->pszRasPbk, pbEapAuthData, dwEapAuthDataSize, ((LPRASENTRY_V500)preRasEntry)->dwCustomAuthKey, &lpRasEapUserIdentity); if (ERROR_SUCCESS != dwRes) { goto exit; } } } CMTRACE1(TEXT("DoTunnelDial: pArgs->pRasDialParams->szUserName is %s"), pArgs->pRasDialParams->szUserName); CMTRACE1(TEXT("DoTunnelDial: pArgs->pRasDialParams->szDomain is %s"), pArgs->pRasDialParams->szDomain); CMTRACE1(TEXT("DoTunnelDial: pArgs->pRasDialParams->szPhoneNumber is %s"), pArgs->pRasDialParams->szPhoneNumber); // // Decode the password before dialing, then re-encode along // with the dial params, which we persist in memory for use // in pause states, etc. // CmDecodePassword(pszPassword); lstrcpyU(pArgs->pRasDialParams->szPassword, pArgs->szPassword); // // Do the dial (PPTP or L2TP) // dwRes = pArgs->rlsRasLink.pfnDial(pArgs->pRasDialExtensions, pArgs->pszRasPbk, pArgs->pRasDialParams, GetRasCallBackType(), GetRasCallBack(pArgs), &pArgs->hrcTunnelConn); CmEncodePassword(pszPassword); CmEncodePassword(pArgs->pRasDialParams->szPassword); CMTRACE1(TEXT("DoTunnelDial() RasDial() returns %u."), dwRes); // // NT5 - Reset the connection type so that it will display properly in // the Connections Folder. This is a temporary solution to #187202 // if (OS_NT5) { MYDBGASSERT(preRasEntry->dwSize >= sizeof(RASENTRY_V500)); ((LPRASENTRY_V500)preRasEntry)->dwType = RASET_Internet; if (pArgs->rlsRasLink.pfnSetEntryProperties) { dwTmp = pArgs->rlsRasLink.pfnSetEntryProperties(pArgs->pszRasPbk, pArgs->pRasDialParams->szEntryName, preRasEntry, preRasEntry->dwSize, NULL, 0); CMTRACE2(TEXT("DoTunnelDial() RasSetEntryProperties(*lpszEntry=%s) returns %u."), MYDBGSTR(pArgs->pRasDialParams->szEntryName,), dwTmp); CMASSERTMSG(dwTmp == ERROR_SUCCESS, TEXT("RasSetEntryProperties for VPN failed")); } } if (dwRes != ERROR_SUCCESS) { pArgs->hrcTunnelConn = NULL; goto exit; } } exit: if (lpRasEapUserIdentity) { MYDBGASSERT(OS_NT5); // NO EAP down-level // // A RasEapUserIdentity struct was allocated, free it via the // appropriate free mechanism. In the WinLogon case we will always // perform the allocation, otherwise we have to go through RAS API. // if (pArgs->lpEapLogonInfo) { CmFree(lpRasEapUserIdentity); } else { if (pArgs->rlsRasLink.pfnFreeEapUserIdentity) { pArgs->rlsRasLink.pfnFreeEapUserIdentity(lpRasEapUserIdentity); } } } CmFree(preRasEntry); // Now we can release the RAS entry structure. #187202 CmFree(pbEapAuthData); return dwRes; } //+--------------------------------------------------------------------------- // // Function: CheckConnect // // Synopsis: double check to make sure all required fields are filled in, such // as username, password, modem, etc. // // Arguments: hwndDlg [dlg window handle] // pArgs pointer to ArgValue structure // pnCtrlFocus: The button whose value is missing will have the focus // // Returns: True is ready to connect // // History: byao Modified 3/7/97 // nickball return BOOLEAN 9/9/98 // //---------------------------------------------------------------------------- BOOL CheckConnect(HWND hwndDlg, ArgsStruct *pArgs, UINT *pnCtrlFocus, BOOL fShowMsg) { LPTSTR pszTmp; BOOL bEnable = TRUE; int nId = 0; UINT nCtrlFocus; BOOL bSavedNoNotify = pArgs->fIgnoreChangeNotification; pArgs->fIgnoreChangeNotification = TRUE; MYDBGASSERT(*pArgs->piniProfile->GetFile()); // // If tunneling, see if we have a tunneling device specified // if (bEnable && IsTunnelEnabled(pArgs)) { lstrcpyU(pArgs->szTunnelDeviceType, RASDT_Vpn); // // Get Tunnel device name from profile // LPTSTR pszTunnelDevice = pArgs->piniProfile->GPPS(c_pszCmSection, c_pszCmEntryTunnelDevice); if (pszTunnelDevice) { lstrcpyU(pArgs->szTunnelDeviceName, pszTunnelDevice); CmFree(pszTunnelDevice); } // // If we don't have a tunnel device, pick one // if (pArgs->szTunnelDeviceName[0] == TEXT('\0')) { // // If we can't pick a tunnel device make sure tunneling is installed // if (!PickTunnelDevice(pArgs,pArgs->szTunnelDeviceType,pArgs->szTunnelDeviceName)) { // // Disable the connect/setting button during component checking and installation // EnableWindow(GetDlgItem(hwndDlg,IDOK),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_PROPERTIES_BUTTON),FALSE); // // Install the PPTP and pick tunnel device one more time // DWORD dwComponentsToCheck = CC_PPTP | CC_RNA | CC_RASRUNNING | CC_TCPIP| CC_CHECK_BINDINGS; if (TRUE == pArgs->bDoNotCheckBindings) { dwComponentsToCheck &= ~CC_CHECK_BINDINGS; } // // PPTP is not installed. // If not unattended, try to install the PPTP and call PickTunnel again // pArgs->dwExitCode = ERROR_PORT_NOT_AVAILABLE; if (!(pArgs->dwFlags & FL_UNATTENDED)) { pArgs->dwExitCode = CheckAndInstallComponents(dwComponentsToCheck, hwndDlg, pArgs->szServiceName); } if (pArgs->dwExitCode != ERROR_SUCCESS || !PickTunnelDevice(pArgs,pArgs->szTunnelDeviceType,pArgs->szTunnelDeviceName)) { bEnable = FALSE; nId = GetPPTPMsgId(); nCtrlFocus = IDCANCEL; } EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_PROPERTIES_BUTTON),TRUE); } pArgs->piniProfile->WPPS(c_pszCmSection, c_pszCmEntryTunnelDevice, pArgs->szTunnelDeviceName); } } // // Next, check the username. // if (GetDlgItem(hwndDlg, IDC_MAIN_USERNAME_EDIT)) { if (bEnable && !pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryUserNameOptional)) { if (!SendDlgItemMessageU(hwndDlg, IDC_MAIN_USERNAME_EDIT, WM_GETTEXTLENGTH, 0, (LPARAM)0)) { bEnable = FALSE; nId = IDMSG_NEED_USERNAME; nCtrlFocus = IDC_MAIN_USERNAME_EDIT; } } } // // Next, check the password. // if (GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT)) { if (!pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryPwdOptional)) { if (!SendDlgItemMessageU(hwndDlg, IDC_MAIN_PASSWORD_EDIT, WM_GETTEXTLENGTH, 0, (LPARAM)0)) { if (bEnable) { bEnable = FALSE; nId = IDMSG_NEED_PASSWORD; nCtrlFocus = IDC_MAIN_PASSWORD_EDIT; } // // Disable "Remember password" check box // if (!pArgs->fHideRememberPassword) { pArgs->fRememberMainPassword = FALSE; CheckDlgButton(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX, FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX), FALSE); if (pArgs->fGlobalCredentialsSupported) { // // Also disable the option buttons // EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_SINGLE_USER), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_ALL_USER), FALSE); } } // // disable the "dial automatically..." checkbox // if (!pArgs->fHideDialAutomatically) { pArgs->fDialAutomatically = FALSE; pArgs->fRememberMainPassword = FALSE; CheckDlgButton(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX, FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), FALSE); } } else { // // Enable the "Remember password" checkbox // if (!pArgs->fHideRememberPassword) { EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX), TRUE); } // // Enable the "dial automatically..." checkbox // if HideDialAutomatically is not set // and if Password is not optional, Remember Password must be true // if ((!pArgs->fHideDialAutomatically) && (pArgs->fRememberMainPassword || pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryPwdOptional))) { EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), TRUE); } } } } // // Next, check the domain. // if (GetDlgItem(hwndDlg, IDC_MAIN_DOMAIN_EDIT)) { if (bEnable && !pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryDomainOptional, TRUE)) { if (!SendDlgItemMessageU(hwndDlg, IDC_MAIN_DOMAIN_EDIT, WM_GETTEXTLENGTH, 0, (LPARAM)0)) { bEnable = FALSE; nId = IDMSG_NEED_DOMAIN; nCtrlFocus = IDC_MAIN_DOMAIN_EDIT; } } } // // Check whether primary phone number is empty -- a quick fix for bug 3123 -byao (4/11/97) // if (!pArgs->IsDirectConnect()) { // // Its not a direct connection, so we must check the phonenumber. If both // szPhoneNumber and szCanonical are blank then we don't have a number. // if (bEnable && IsBlankString(pArgs->aDialInfo[0].szPhoneNumber) && IsBlankString(pArgs->aDialInfo[0].szCanonical)) { bEnable = FALSE; if (pArgs->fNeedConfigureTapi) { nId = IDMSG_NEED_CONFIGURE_TAPI; } else { // // If direct and dial-up,the message should include the // possibility of direct connection, otherwise use // the standard need a phone number message // if (pArgs->IsBothConnTypeSupported()) { nId = IDMSG_NEED_PHONE_DIRECT; } else { nId = IDMSG_NEED_PHONE_DIAL; } } nCtrlFocus = IDC_MAIN_PROPERTIES_BUTTON; } } // // If tunneling is enabled and we are using a VPN file, make sure // the user has selected a tunnel endpoint. // if (bEnable && IsTunnelEnabled(pArgs) && pArgs->pszVpnFile) { LPTSTR pszTunnelAddress = pArgs->piniBothNonFav->GPPS(c_pszCmSection, c_pszCmEntryTunnelAddress); if ((NULL == pszTunnelAddress) || (TEXT('\0') == pszTunnelAddress[0])) { bEnable = FALSE; nId = IDMSG_PICK_VPN_ADDRESS; nCtrlFocus = IDC_MAIN_PROPERTIES_BUTTON; } CmFree(pszTunnelAddress); } if (bEnable) { // // well, now we can set the focus to the 'connect' button // Display ready to dial message // nCtrlFocus = IDOK; nId = IDMSG_READY; } if (pnCtrlFocus) { *pnCtrlFocus = nCtrlFocus; } pszTmp = CmFmtMsg(g_hInst,nId); if (NULL == pszTmp) { return FALSE; } SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, pszTmp); // // If necessary, throw a message box at the user. // if (!bEnable && fShowMsg) { MessageBoxEx(hwndDlg, pszTmp, pArgs->szServiceName, MB_OK|MB_ICONINFORMATION, LANG_USER_DEFAULT); } CmFree(pszTmp); pArgs->fIgnoreChangeNotification = bSavedNoNotify; // // Something went wrong in the config. we need to recheck the // configs next time we run CM. // if (GetPPTPMsgId() == nId) // not an assignment, stay left { ClearComponentsChecked(); } return bEnable; } void MainSetDefaultButton(HWND hwndDlg, UINT nCtrlId) { switch (nCtrlId) { case IDCANCEL: case IDC_MAIN_PROPERTIES_BUTTON: break; default: nCtrlId = IDOK; break; } SendMessageU(hwndDlg, DM_SETDEFID, (WPARAM)nCtrlId, 0); } //+--------------------------------------------------------------------------- // // Function: SetMainDlgUserInfo // // Synopsis: Set user info in the main dlg. // // Arguments: pArgs - the ArgStruct * // hwndDlg - the main dlg // // Returns: NONE // // History: henryt Created 5/5/97 // //---------------------------------------------------------------------------- void SetMainDlgUserInfo( ArgsStruct *pArgs, HWND hwndDlg ) { HWND hwndTemp = NULL; // // Fill in the edit controls that exist // Set the textbox modification flag. For Win9x compatibily issues we have to explicitly // call SendMessageU instead of using the Edit_SetModify macro. The flag is used to see // if the user has manually changed the contents of the edit boxes. // if (pArgs->fAccessPointsEnabled) { // // This fuction populates the combo box passed to it with info from the reg // ShowAccessPointInfoFromReg(pArgs, hwndDlg, IDC_MAIN_ACCESSPOINT_COMBO); } hwndTemp = GetDlgItem(hwndDlg, IDC_MAIN_USERNAME_EDIT); if (hwndTemp) { SetDlgItemTextU(hwndDlg, IDC_MAIN_USERNAME_EDIT, pArgs->szUserName); SendMessageU(hwndTemp, EM_SETMODIFY, (WPARAM)FALSE, 0L); } hwndTemp = GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT); if (hwndTemp) { CmDecodePassword(pArgs->szPassword); SetDlgItemTextU(hwndDlg, IDC_MAIN_PASSWORD_EDIT, pArgs->szPassword); CmEncodePassword(pArgs->szPassword); SendMessageU(hwndTemp, EM_SETMODIFY, (WPARAM)FALSE, 0L); } hwndTemp = GetDlgItem(hwndDlg, IDC_MAIN_DOMAIN_EDIT); if (hwndTemp) // !pArgs->fHideDomain) { SetDlgItemTextU(hwndDlg, IDC_MAIN_DOMAIN_EDIT, pArgs->szDomain); SendMessageU(hwndTemp, EM_SETMODIFY, (WPARAM)FALSE, 0L); } } //+--------------------------------------------------------------------------- // // Function: OnResetPassword // // Synopsis: Handle reset password. // // Arguments: pArgs - the ArgStruct * // hwndDlg - the main dlg // // Returns: BOOL -- TRUE if SUCCEEDED // // History: henryt Created 5/6/97 // //---------------------------------------------------------------------------- BOOL OnResetPassword(HWND hwndDlg, ArgsStruct *pArgs) { LPTSTR pszArgs = NULL; LPTSTR pszCmd = NULL; BOOL bReturn = FALSE; MYDBGASSERT(pArgs); MYDBGASSERT(pArgs->pszResetPasswdExe); // // Get the latest password data from the edit control // and obfuscate its contents so that connect actions // can't retrieve it. // GetPasswordFromEdit(pArgs); // fills pArgs->szPassword ObfuscatePasswordEdit(pArgs); if (pArgs && pArgs->pszResetPasswdExe) { if (CmParsePath(pArgs->pszResetPasswdExe, pArgs->piniService->GetFile(), &pszCmd, &pszArgs)) { pArgs->Log.Log(PASSWORD_RESET_EVENT, pszCmd); SHELLEXECUTEINFO ShellExInfo; ZeroMemory(&ShellExInfo, sizeof(SHELLEXECUTEINFO)); // // Fill in the Execute Struct // ShellExInfo.cbSize = sizeof(SHELLEXECUTEINFO); ShellExInfo.hwnd = hwndDlg; ShellExInfo.lpVerb = TEXT("open"); ShellExInfo.lpFile = pszCmd; ShellExInfo.lpParameters = pszArgs; ShellExInfo.nShow = SW_SHOWNORMAL; bReturn = pArgs->m_ShellDll.ExecuteEx(&ShellExInfo); } CmFree(pszCmd); CmFree(pszArgs); } #ifdef DEBUG CMASSERTMSG(bReturn, TEXT("OnResetPassword() - ShellExecute failed.")); #endif DeObfuscatePasswordEdit(pArgs); return bReturn; } //+--------------------------------------------------------------------------- // // Function: OnCustom // // Synopsis: Handle custom button // // Arguments: pArgs - the ArgStruct * // hwndDlg - the main dlg // // Returns: NONE // // History: t-adnani Created 6/26/99 // //---------------------------------------------------------------------------- void OnCustom( HWND hwndDlg, ArgsStruct *pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { return; } pArgs->Log.Log(CUSTOM_BUTTON_EVENT); // // Get the latest password data from the edit control // and obfuscate its contents so that connect actions // can't retrieve it. // GetPasswordFromEdit(pArgs); // fills pArgs->szPassword ObfuscatePasswordEdit(pArgs); // // Run the CustomButton actions // int iTextBoxLength = (int) SendDlgItemMessage(hwndDlg, IDC_MAIN_STATUS_DISPLAY, WM_GETTEXTLENGTH, 0, (LPARAM)0) + 1; TCHAR *pszTextBoxContents = (TCHAR *) CmMalloc(iTextBoxLength * sizeof(TCHAR)); if (pszTextBoxContents) { GetDlgItemText(hwndDlg, IDC_MAIN_STATUS_DISPLAY, pszTextBoxContents, iTextBoxLength); } CActionList CustomActList; CustomActList.Append(pArgs->piniService, c_pszCmSectionCustom); if (!CustomActList.RunAccordType(hwndDlg, pArgs)) { // // Connect action failed // } else { if (pszTextBoxContents) { SetDlgItemText(hwndDlg, IDC_MAIN_STATUS_DISPLAY, pszTextBoxContents); } } CmFree(pszTextBoxContents); DeObfuscatePasswordEdit(pArgs); } //---------------------------------------------------------------------------- // // Function: SetupInternalInfo // // Synopsis: Load system dll's and init ArgsStruct with info from cmp/cms. // // Arguments: pArgs - the ArgStruct * // hwndDlg - the main dlg // // Returns: NONE // // History: henryt created 8/13/97 // //---------------------------------------------------------------------------- BOOL SetupInternalInfo( ArgsStruct *pArgs, HWND hwndDlg ) { HCURSOR hcursorPrev = SetCursor(LoadCursorU(NULL,IDC_WAIT)); BOOL fRet = FALSE; // // should we check if TCP is bound to PPP? // pArgs->bDoNotCheckBindings = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryDoNotCheckBindings, FALSE); DWORD dwComponentsToCheck = CC_RNA | CC_TCPIP | CC_RASRUNNING | CC_SCRIPTING | CC_CHECK_BINDINGS; if (TRUE == pArgs->bDoNotCheckBindings) { // // Do not check if TCP is bound to PPP // dwComponentsToCheck &= ~CC_CHECK_BINDINGS; } #if 0 // Don't do this until the user gets into the app. /* // // If current connection type is dial-up (not Direct means Dial-up), // then check modem // if (!pArgs->IsDirectConnect()) { dwComponentsToCheck |= CC_MODEM; } */ #endif if (TRUE == IsTunnelEnabled(pArgs)) { dwComponentsToCheck |= CC_PPTP; } // // should we check OS components, regardless what is in the registry key // Default is use the registry key // BOOL fIgnoreRegKey = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryCheckOsComponents, FALSE); // // If fIgnoreRegKey is TRUE, Do not bother looking ComponentsChecked from registry. // in 'Unattended Dialing' mode, check only, do not try to install // pArgs->dwExitCode = CheckAndInstallComponents( dwComponentsToCheck, hwndDlg, pArgs->szServiceName, fIgnoreRegKey, pArgs->dwFlags & FL_UNATTENDED); if (pArgs->dwExitCode != ERROR_SUCCESS ) { goto done; } // // If we haven't loaded RAS yet, do so now. // if (!IsRasLoaded(&(pArgs->rlsRasLink))) { if (!LinkToRas(&pArgs->rlsRasLink)) { if (pArgs->dwFlags & FL_UNATTENDED) { goto done; } // // Something terrible happened! We want to check our configs and install // necessary components now. // dwComponentsToCheck = CC_RNA | CC_RASRUNNING | CC_TCPIP; if (TRUE != pArgs->bDoNotCheckBindings) { dwComponentsToCheck |= CC_CHECK_BINDINGS; } pArgs->dwExitCode = CheckAndInstallComponents(dwComponentsToCheck, hwndDlg, pArgs->szServiceName); if (pArgs->dwExitCode != ERROR_SUCCESS || !LinkToRas(&pArgs->rlsRasLink)) { goto done; } } } // // Load properties data // LoadProperties(pArgs); // // Get phone info(phone #'s, etc) // CheckConnect will check for empty phone number // LoadPhoneInfoFromProfile(pArgs); fRet = TRUE; done: SetCursor(hcursorPrev); return fRet; } //---------------------------------------------------------------------------- // // Function: OnMainLoadStartupInfo // // Synopsis: Load the startup info for the main dlg(after WM_INITDIALOG). // This includes loading system dll's and setting up the UI. // // Arguments: hwndDlg - the main dlg // pArgs - the ArgStruct * // // Returns: NONE // // History: henryt created 8/13/97 // //---------------------------------------------------------------------------- void OnMainLoadStartupInfo( HWND hwndDlg, ArgsStruct *pArgs ) { UINT i; UINT nCtrlFocus; BOOL fSaveNoNotify = pArgs->fIgnoreChangeNotification; pArgs->fStartupInfoLoaded = TRUE; // // if failed to load dll's, etc... // if (!SetupInternalInfo(pArgs, hwndDlg)) { PostMessageU(hwndDlg, WM_COMMAND, IDCANCEL,0); return; } // // Set the length limit for the edit controls that exist // if (GetDlgItem(hwndDlg, IDC_MAIN_USERNAME_EDIT)) { i = (UINT)pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxUserName, UNLEN); if (i <= 0) { i = UNLEN; // username } SendDlgItemMessageU(hwndDlg, IDC_MAIN_USERNAME_EDIT, EM_SETLIMITTEXT, __min(UNLEN, i), 0); } if (GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT)) { i = (UINT)pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxPassword, PWLEN); if (i <= 0) { i = PWLEN; // password } SendDlgItemMessageU(hwndDlg, IDC_MAIN_PASSWORD_EDIT, EM_SETLIMITTEXT, __min(PWLEN, i), 0); } if (GetDlgItem(hwndDlg, IDC_MAIN_DOMAIN_EDIT)) // !pArgs->fHideDomain) { i = (UINT)pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxDomain, DNLEN); if (i <= 0) { i = DNLEN; // domain } SendDlgItemMessageU(hwndDlg, IDC_MAIN_DOMAIN_EDIT, EM_SETLIMITTEXT, __min(DNLEN, i), 0); } // // if there's no service msg text, we need to hide and disable the control // so that context help doesn't work. // if (!GetWindowTextLengthU(GetDlgItem(hwndDlg, IDC_MAIN_MESSAGE_DISPLAY))) { ShowWindow(GetDlgItem(hwndDlg, IDC_MAIN_MESSAGE_DISPLAY), SW_HIDE); EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_MESSAGE_DISPLAY), FALSE); } // // display the user info // pArgs->fIgnoreChangeNotification = TRUE; SetMainDlgUserInfo(pArgs, hwndDlg); pArgs->fIgnoreChangeNotification = fSaveNoNotify; // // init "Remember password" // if (pArgs->fHideRememberPassword) { // // disable and hide the checkbox if the ISP doesn't use this feature // //ShowWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX), SW_HIDE); //EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX), FALSE); } else { CheckDlgButton(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX, pArgs->fRememberMainPassword); // // Don't care if the pArgs->fRememberMainPassword is set // since controls will get disabled later // Set the save as option buttons according to what the current // deafult is // SetCredentialUIOptionBasedOnDefaultCreds(pArgs, hwndDlg); } // // init "Dial automatically..." // if (pArgs->fHideDialAutomatically) { // // disable and hide the checkbox if the ISP doesn't use this feature // //ShowWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), SW_HIDE); //EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), FALSE); } else { CheckDlgButton(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX, pArgs->fDialAutomatically); } // // Check the main dlg status and set the default button and focus accordingly // BOOL bReady = CheckConnect(hwndDlg,pArgs,&nCtrlFocus); MainSetDefaultButton(hwndDlg, nCtrlFocus); SetFocus(GetDlgItem(hwndDlg, nCtrlFocus)); // // Check if we want to dial without prompting user // if so, send the button click to connect button // We also want to dial if the user isn't logged on (ICS case) // if (bReady) { if (pArgs->fDialAutomatically || pArgs->dwFlags & FL_RECONNECT || pArgs->dwFlags & FL_UNATTENDED || ((CM_LOGON_TYPE_WINLOGON == pArgs->dwWinLogonType) && (pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryUseWinLogonCredentials, TRUE)))) { PostMessageU(hwndDlg, WM_COMMAND, IDOK, 0); } } else { // // there are settings missing. // silently fail in unattended dial, set exit code // if (pArgs->dwFlags & FL_UNATTENDED) { pArgs->dwExitCode = ERROR_WRONG_INFO_SPECIFIED; PostMessageU(hwndDlg, WM_COMMAND, IDCANCEL,0); } } CM_SET_TIMING_INTERVAL("OnMainLoadStartupInfo - Complete"); } //+---------------------------------------------------------------------------- // // Function: CreateCustomButtonNextToTextBox // // Synopsis: Creates a pushbutton next to the specified text box // // Arguments: HWND hwndDlg - Dialog Handle // HWND hwndTextBox - TextBox Handle // LPTSTR pszTitle - Push Button Title // LPTSTR pszToolTip - Push Button Tooltip // UINT uButtonID - Control ID of Button to create // // Returns: Nothing // // History: t-adnani Created Header 6/28/99 // //+---------------------------------------------------------------------------- void CreateCustomButtonNextToTextBox( HWND hwndDlg, // Dialog Handle HWND hwndTextBox, // TextBox Handle LPTSTR pszTitle, // Caption LPTSTR pszToolTip, // ToolTip Text UINT uButtonID // ButtonID ) { RECT rt; POINT pt1, pt2, ptTextBox1, ptTextBox2; HFONT hfont; HWND hwndButton; // // Get the rectangle and convert to points before we reduce its size. // GetWindowRect(hwndTextBox, &rt); pt1.x = rt.left; pt1.y = rt.top; pt2.x = rt.right; pt2.y = rt.bottom; ScreenToClient(hwndDlg, &pt1); ScreenToClient(hwndDlg, &pt2); // // Then calculate the points for reduction // ptTextBox1.x = rt.left; ptTextBox1.y = rt.top; ptTextBox2.x = rt.right; ptTextBox2.y = rt.bottom; ScreenToClient(hwndDlg, &ptTextBox1); ScreenToClient(hwndDlg, &ptTextBox2); // // Make the text box smaller // MoveWindow(hwndTextBox, ptTextBox1.x, ptTextBox1.y, ptTextBox2.x - ptTextBox1.x - CUSTOM_BUTTON_WIDTH - 7, ptTextBox2.y - ptTextBox1.y, TRUE); // // Create the button // hwndButton = CreateWindowExU(0, TEXT("button"), pszTitle, BS_PUSHBUTTON|WS_VISIBLE|WS_CHILD|WS_TABSTOP, pt2.x - CUSTOM_BUTTON_WIDTH, ptTextBox1.y, CUSTOM_BUTTON_WIDTH, ptTextBox2.y-ptTextBox1.y, hwndDlg, (HMENU)UIntToPtr(uButtonID), g_hInst, NULL); if (NULL == hwndButton) { CMTRACE1(TEXT("CreateCustomButtonNextToTextBox() CreateWindowExU() failed, GLE=%u."),GetLastError()); } // // Set the font on the button // hfont = (HFONT)SendMessageU(hwndTextBox, WM_GETFONT, 0, 0); if (NULL == hfont) { CMTRACE1(TEXT("CreateCustomButtonNextToTextBox() WM_GETFONT failed, GLE=%u."),GetLastError()); return; } SendMessageU(hwndButton, WM_SETFONT, (WPARAM)hfont, MAKELPARAM(TRUE,0)); if (pszToolTip == NULL) { return; } // // do the tool tip // HWND hwndTT = CreateWindowExU(0, TOOLTIPS_CLASS, TEXT(""), TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, hwndDlg, (HMENU) NULL, g_hInst, NULL); CMTRACE2(TEXT("CreateCustomButtonNextToTextBox() hwndTT is %u and IsWindow returns %u"),hwndTT, IsWindow(hwndButton)); if (NULL == hwndTT) { CMTRACE1(TEXT("CreateCustomButtonNextToTextBox() CreateWindowExU() failed, GLE=%u."),GetLastError()); MYDBGASSERT(hwndTT); return; } TOOLINFO ti; // tool information ti.cbSize = sizeof(TOOLINFO); ti.uFlags = TTF_IDISHWND | TTF_CENTERTIP | TTF_SUBCLASS; ti.hwnd = hwndDlg; ti.hinst = g_hInst; ti.uId = (UINT_PTR) hwndButton; ti.lpszText = pszToolTip; SendMessageU(hwndTT, TTM_ADDTOOL, 0, (LPARAM) (LPTOOLINFO) &ti); CMTRACE2(TEXT("CreateCustomButtonNextToTextBox() hwndTT is %u and IsWindow returns %u"),hwndTT, IsWindow(hwndButton)); return; } //+--------------------------------------------------------------------------- // // Function: OnMainInit // // Synopsis: Process the WM_INITDIALOG message // initialization function for Main dialog box // // Arguments: hwndDlg - the main dlg // pArgs - the ArgStruct * // // Returns: NONE // // History: byao Modified 5/9/97 // Added code to handle "Unattended Dial" and "Dial with Connectoid" // //---------------------------------------------------------------------------- void OnMainInit(HWND hwndDlg, ArgsStruct *pArgs) { RECT rDlg; RECT rWorkArea; LPTSTR pszTitle; SetForegroundWindow(hwndDlg); // // load the icons and bitmaps // LoadIconsAndBitmaps(pArgs, hwndDlg); // // Use long sevice name as title text for signin window, // pszTitle = CmStrCpyAlloc(pArgs->szServiceName); SetWindowTextU(hwndDlg, pszTitle); CmFree(pszTitle); // // Set the msg for the main dlg for profile dialing // LPTSTR pszMsg = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryServiceMessage); SetDlgItemTextU(hwndDlg, IDC_MAIN_MESSAGE_DISPLAY, pszMsg); CmFree(pszMsg); // // Show "remember password" checkbox? // if (IsLogonAsSystem()) { // // If the program is running in the system account, hide the checkbox // Bug 196184: big security hole logging onto box with cm // pArgs->fHideRememberPassword = TRUE; // // Another big security hole by launching help files from winlogon. // See NTRAID 429678 for details. // EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_HELP_BUTTON), FALSE); } else { pArgs->fHideRememberPassword = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideRememberPwd); } // // See if the Internet Password should be hidden, take HideRemember // value as the default if no actual value is specified in the .CMS // The Internet Password can be saved regardless of the logon context // pArgs->fHideRememberInetPassword = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideRememberInetPwd, pArgs->fHideRememberPassword); // // show "dial automatically" checkbox? // // if "hide remember password", then we also want to hide "dial automatically" // pArgs->fHideDialAutomatically = (pArgs->fHideRememberPassword? TRUE : pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideDialAuto)); // Get the dialog rect and the available work area. GetWindowRect(hwndDlg,&rDlg); if (SystemParametersInfoA(SPI_GETWORKAREA,0,&rWorkArea,0)) { MoveWindow(hwndDlg, rWorkArea.left + ((rWorkArea.right-rWorkArea.left)-(rDlg.right-rDlg.left))/2, rWorkArea.top + ((rWorkArea.bottom-rWorkArea.top)-(rDlg.bottom-rDlg.top))/2, rDlg.right-rDlg.left, rDlg.bottom-rDlg.top, FALSE); } // // hide all the hidden controls asap // if (pArgs->fHideRememberPassword) { // // disable and hide the checkbox if the ISP doesn't use this feature // ShowWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX), SW_HIDE); EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX), FALSE); // // Even though we are hiding the remember password box, // we should not hide these two controls as they might not exist on the // dialog. fGlobalCredentialsSupported controls which dialog templates get loaded and // if the flag is FALSE then the dialog template doesn't have these controls // thus there is no reason to hide them. // if (pArgs->fGlobalCredentialsSupported) { // // Also hide the option buttons // ShowWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_SINGLE_USER), SW_HIDE); EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_SINGLE_USER), FALSE); ShowWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_ALL_USER), SW_HIDE); EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_ALL_USER), FALSE); } } else { // // Here we don't care if pArgs->fRememberMainPassword is set, because // these controls will get disabled later, but we still need to set // the default option. // SetCredentialUIOptionBasedOnDefaultCreds(pArgs, hwndDlg ); } if (pArgs->fHideDialAutomatically) { // // disable and hide the checkbox if the ISP doesn't use this feature // ShowWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), SW_HIDE); EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), FALSE); } // // Show the custom button? // // NT #368810 // If logged on in the system account, don't do dynamic buttons // if (!IsLogonAsSystem() && GetDlgItem(hwndDlg, IDC_MAIN_USERNAME_EDIT)) { LPTSTR pszTmp = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryCustomButtonText); if (pszTmp && *pszTmp) { LPTSTR pszToolTip = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryCustomButtonToolTip); CMTRACE(TEXT("Creating Custom Button")); CreateCustomButtonNextToTextBox(hwndDlg, GetDlgItem(hwndDlg, IDC_MAIN_USERNAME_EDIT), pszTmp, *pszToolTip ? pszToolTip : NULL, IDC_MAIN_CUSTOM); CmFree(pszToolTip); } CmFree(pszTmp); } // // Show the reset password button? // if (!IsLogonAsSystem() && GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT)) { LPTSTR pszTmp = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryResetPassword); if (pszTmp && *pszTmp) { DWORD dwTmp; DWORD dwLen = (MAX_PATH * 2); pArgs->pszResetPasswdExe = (LPTSTR) CmMalloc(sizeof(TCHAR) * dwLen); if (pArgs->pszResetPasswdExe) { // // Expand any environment strings that may exist // CMTRACE1(TEXT("Expanding ResetPassword environment string as %s"), pszTmp); dwTmp = ExpandEnvironmentStringsU(pszTmp, pArgs->pszResetPasswdExe, dwLen); MYDBGASSERT(dwTmp <= dwLen); // // As long as expansion succeeded, pass along the result // if (dwTmp <= dwLen) { pszTitle = CmLoadString(g_hInst, IDS_RESETPASSWORD); CMTRACE((TEXT("Showing ResetPassword button for %s"), pArgs->pszResetPasswdExe)); CreateCustomButtonNextToTextBox(hwndDlg, GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT), pszTitle, (LPTSTR)MAKEINTRESOURCE(IDS_NEW_PASSWORD_TOOLTIP), IDC_MAIN_RESET_PASSWORD); CmFree(pszTitle); } } } CmFree(pszTmp); } // // Notify user that we are intializing // AppendStatusPane(hwndDlg,IDMSG_INITIALIZING); // // Initialize system menu // HMENU hMenu = GetSystemMenu(hwndDlg, FALSE); MYDBGASSERT(hMenu); // Delete size and maximize menuitems. These are // not appropriate for a dialog with a no-resize frame. DeleteMenu(hMenu, SC_SIZE, MF_BYCOMMAND); DeleteMenu(hMenu, SC_MAXIMIZE, MF_BYCOMMAND); EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED); // // See if we are hiding any InetLogon controls // if (IsTunnelEnabled(pArgs) && !pArgs->fUseSameUserName) { pArgs->fHideInetUsername = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideInetUserName); pArgs->fHideInetPassword = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideInetPassword); } // // set timer // pArgs->nTimerId = SetTimer(hwndDlg,1,TIMER_RATE,NULL); } // // map state to frame: splash???? // VOID MapStateToFrame(ArgsStruct * pArgs) { static ProgState psOldFrame = PS_Interactive; ProgState psNewFrame = pArgs->psState; if (psNewFrame == PS_Dialing || psNewFrame == PS_TunnelDialing) { // // If we are dialing anything other than the primary number // switch the state to RedialFrame // RedialFrame is a misnomer - this is the frame that is displayed // when dialing backup number. It is not used when Redialing the // primary number again // if (pArgs->nDialIdx > 0) { psNewFrame = PS_RedialFrame; } } if (pArgs->pCtr && psNewFrame != psOldFrame) { psOldFrame = psNewFrame; // // don't check for failure here - nothing we can do. // pArgs->pCtr->MapStateToFrame(psOldFrame); } } // // SetInteractive: enable most of the windows and buttons so user can interact with // connection manager again // void SetInteractive(HWND hwndDlg, ArgsStruct *pArgs) { if (pArgs->dwFlags & FL_UNATTENDED) { // // When we are unattended mode we don't want to put the UI into // interactive mode and wait for user input. Since the unattended // UI is now hidden, this would put up the UI waiting for user // interaction even though the UI was invisible. Instead we // will set the state to Interactive and post a message to cancel // the dialer. // CMTRACE(TEXT("SetInteractive called while in unattended mode, posting a message to cancel")); pArgs->psState = PS_Interactive; PostMessageU(hwndDlg, WM_COMMAND, IDCANCEL, ERROR_CANCELLED); } else { pArgs->psState = PS_Interactive; MapStateToFrame(pArgs); pArgs->dwStateStartTime = GetTickCount(); EnableWindow(GetDlgItem(hwndDlg,IDOK),TRUE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_PROPERTIES_BUTTON),TRUE); // // Enable edit controls as necessary // if (GetDlgItem(hwndDlg, IDC_MAIN_ACCESSPOINT_COMBO)) { EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_ACCESSPOINT_STATIC),TRUE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_ACCESSPOINT_COMBO),TRUE); } if (GetDlgItem(hwndDlg, IDC_MAIN_USERNAME_EDIT)) { EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_USERNAME_EDIT),TRUE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_USERNAME_STATIC),TRUE); } if (GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT)) { EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_PASSWORD_EDIT),TRUE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_PASSWORD_STATIC),TRUE); } if (GetDlgItem(hwndDlg, IDC_MAIN_DOMAIN_EDIT)) // !pArgs->fHideDomain) { EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_DOMAIN_EDIT),TRUE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_DOMAIN_STATIC),TRUE); } if (pArgs->hwndResetPasswdButton) { EnableWindow(pArgs->hwndResetPasswdButton, TRUE); } if (!pArgs->fHideRememberPassword) { EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX), TRUE); if (pArgs->fGlobalCredentialsSupported && pArgs->fRememberMainPassword) { // // Also enable the option buttons // EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_SINGLE_USER), TRUE); EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_ALL_USER), TRUE); } } if ((!pArgs->fHideDialAutomatically) && (pArgs->fRememberMainPassword || pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryPwdOptional))) { EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), TRUE); } // // Set the default button // SendMessageU(hwndDlg, DM_SETDEFID, (WPARAM)IDOK, 0); SetFocus(GetDlgItem(hwndDlg,IDOK)); } DeObfuscatePasswordEdit(pArgs); } //+---------------------------------------------------------------------------- // // Function: SetWatchHandles // // Synopsis: Handles the messy details of Duplicating each of the Watch // handles so that they can be accessed by the CMMON process. // The list of handles is assumed to be NULL terminated. // // Arguments: HANDLE *phOldHandles - Ptr to the current handle list. // HANDLE *phNewHandles - Ptr to storage for duplicted handles. // HWND hwndMon - HWND in the target process. // // Returns: BOOL - TRUE on success // // History: nickball Created 2/11/98 // //+---------------------------------------------------------------------------- BOOL SetWatchHandles( IN HANDLE *phOldHandles, OUT HANDLE *phNewHandles, IN HWND hwndMon) { MYDBGASSERT(phOldHandles); MYDBGASSERT(phNewHandles); MYDBGASSERT(hwndMon); BOOL bReturn = TRUE; if (NULL == phOldHandles || NULL == phNewHandles || NULL == hwndMon) { return FALSE; } // // First we need to get the Handle of our current process // DWORD dwProcessId = GetCurrentProcessId(); HANDLE hSourceProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId); // // Now the handle of the target process // GetWindowThreadProcessId(hwndMon, &dwProcessId); HANDLE hTargetProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, dwProcessId); // // Loop through our handles list and duplicate // DWORD dwIdx = 0; for (dwIdx = 0; phOldHandles[dwIdx]; dwIdx++) { if (FALSE == DuplicateHandle(hSourceProcess, phOldHandles[dwIdx], // Val hTargetProcess, &phNewHandles[dwIdx], // Ptr NULL, FALSE, DUPLICATE_SAME_ACCESS)) { CMTRACE1(TEXT("SetWatchHandles() - DuplicateHandles failed on item %u"), dwIdx); MYDBGASSERT(FALSE); bReturn = FALSE; break; } } MYDBGASSERT(dwIdx); // Don't call if you don't have handles to duplicate // // Cleanup // if (!bReturn) { // we failed during Handle Duplication... must clean up while (dwIdx > 0) { CloseHandle(phNewHandles[--dwIdx]); } } CloseHandle(hTargetProcess); CloseHandle(hSourceProcess); return bReturn; } //+---------------------------------------------------------------------------- // // Function: ConnectMonitor // // Synopsis: Encapsulates the details of launching CMMON, waiting for load // verification, and providing it with connect data. // // Arguments: ArgsStruct *pArgs - Ptr to global args struct // // Returns: HRESULT - Failure code // // History: nickball Created 2/9/98 // //+---------------------------------------------------------------------------- HRESULT ConnectMonitor(ArgsStruct *pArgs) { LRESULT lRes = ERROR_SUCCESS; BOOL fMonReady = FALSE; HWND hwndMon = NULL; TCHAR szDesktopName[MAX_PATH]; TCHAR szWinDesktop[MAX_PATH]; // // Determine if CMMON is running // if (SUCCEEDED(pArgs->pConnTable->GetMonitorWnd(&hwndMon))) { fMonReady = IsWindow(hwndMon); } // // If not, launch it // if (FALSE == fMonReady) { // // Create launch event // HANDLE hEvent = CreateEventU(NULL, TRUE, FALSE, c_pszCmMonReadyEvent); if (NULL == hEvent) { MYDBGASSERT(FALSE); lRes = GetLastError(); } else { STARTUPINFO StartupInfo; PROCESS_INFORMATION ProcessInfo; TCHAR szCommandLine[2 * MAX_PATH + 3]; // // Launch c_pszCmMonExeName // ZeroMemory(&ProcessInfo, sizeof(ProcessInfo)); ZeroMemory(&StartupInfo, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); // // If this is win2k or whistler, then we don't want to launch cmmon32.exe onto the users // desktop since it is a security hole to have a system process with a window on the users // desktop. This window could be attacked by WM_TIMER and other messages ... // But in case of ICS (no user is logged on), just launch CMMON in normally by leaving // StartupInfo.lpDesktop = NULL. By leaving this NULL the new process inherits // the desktop and window station of its parent process.This makes it work with // ICS when no user is logged-on. Otherwise CM never gets the event back from // CMMON because it's on a different desktop. // if (OS_NT5 && IsLogonAsSystem() && (CM_LOGON_TYPE_ICS != pArgs->dwWinLogonType)) { DWORD cb; HDESK hDesk = GetThreadDesktop(GetCurrentThreadId()); // // Get the name of the desktop. Normally returns default or Winlogon or system or WinNT // szDesktopName[0] = 0; if (GetUserObjectInformation(hDesk, UOI_NAME, szDesktopName, sizeof(szDesktopName), &cb)) { lstrcpyU(szWinDesktop, TEXT("Winsta0\\")); lstrcatU(szWinDesktop, szDesktopName); StartupInfo.lpDesktop = szWinDesktop; StartupInfo.wShowWindow = SW_SHOW; CMTRACE1(TEXT("ConnectMonitor - running under system account, so launching cmmon32.exe onto Desktop = %s"), MYDBGSTR(StartupInfo.lpDesktop)); } else { // // If we are here, cmmon32.exe probably isn't going to be able to communicate with // cmdial32.dll which means the handoff between the two will fail and the call will be // aborted. // CMASSERTMSG(FALSE, TEXT("ConnectMonitor -- GetUserObjectInformation failed.")); } } else if (OS_NT4 && IsLogonAsSystem()) { // // We are less concerned about the security risk on NT4 and more concerned with the loss // of the functionality that cmmon32.exe provides to the user. Thus we will push the // cmmon32.exe window onto the user's desktop. // StartupInfo.lpDesktop = TEXT("Winsta0\\Default"); StartupInfo.wShowWindow = SW_SHOW; CMTRACE1(TEXT("ConnectMonitor - running on system account on NT4, so launching cmmon32.exe onto Desktop = %s"), MYDBGSTR(StartupInfo.lpDesktop )); } ZeroMemory(&szCommandLine, sizeof(szCommandLine)); szCommandLine[0] = TEXT('"'); if (0 == GetSystemDirectoryU(szCommandLine + 1, 2 * MAX_PATH)) { lRes = GetLastError(); CMTRACE1(TEXT("ConnectMonitor() GetSystemDirectoryU(), GLE=%u."), lRes); return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } // // Set Application name to NULL, set command line to the executable name // Thus CreateProcess will search the path for the executable // lstrcatU(szCommandLine, TEXT("\\")); lstrcatU(szCommandLine, c_pszCmMonExeName); lstrcatU(szCommandLine, TEXT("\"")); CMTRACE1(TEXT("ConnectMonitor() - Launching %s"), szCommandLine); if (NULL == CreateProcessU(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInfo)) { lRes = GetLastError(); CMTRACE2(TEXT("ConnectMonitor() CreateProcess() of %s failed, GLE=%u."), c_pszCmMonExeName, lRes); } else { // // Wait for event to be signaled, that CMMON is up // DWORD dwWait = WaitForSingleObject(hEvent, MAX_OBJECT_WAIT); if (WAIT_OBJECT_0 != dwWait) { if (WAIT_TIMEOUT == dwWait) { lRes = ERROR_TIMEOUT; } else { lRes = GetLastError(); } } else { fMonReady = TRUE; } // // Close Process handles. Note, we don't use these handles for // duplicating handles in order to maintain a common code path // regardless of whether CMMON was up already. // CloseHandle(ProcessInfo.hProcess); CloseHandle(ProcessInfo.hThread); } CloseHandle(hEvent); } } if (fMonReady) { // // Get the hwnd for CMMON. Note: CMMON is expected to set // the hwnd in the table before it signals the ready event. // if (FAILED(pArgs->pConnTable->GetMonitorWnd(&hwndMon))) { CMTRACE(TEXT("ConnectMonitor() - No Monitor HWND in table")); return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } // // Make sure the HWND for CMMON is valid before trying to send data. // if (!IsWindow(hwndMon)) { MSG msg; HANDLE hHandle = GetCurrentProcess(); // // Sometimes it takes a few ticks for us to get a positive response // from IsWindow, so loop and pump messages while we are waiting. // while (hHandle && (MsgWaitForMultipleObjects(1, &hHandle, FALSE, MAX_OBJECT_WAIT, QS_ALLINPUT) == (WAIT_OBJECT_0 + 1))) { while (PeekMessageU(&msg, NULL, 0, 0, PM_REMOVE)) { CMTRACE(TEXT("ConnectMonitor() - Waiting for IsWindow(hwndMon) - got Message")); TranslateMessage(&msg); DispatchMessageU(&msg); } // // If the window is valid, we can go. Otherwise, keep pumping. // if (IsWindow(hwndMon)) { break; } } if (FALSE == IsWindow(hwndMon)) { CMTRACE(TEXT("ConnectMonitor() - Monitor HWND in table is not valid")); return HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } } // // Allocate buffer for CONNECTED_INFO, including extension for Watch Process list // DWORD dwWatchCount = GetWatchCount(pArgs); DWORD dwDataSize = sizeof(CM_CONNECTED_INFO) + (dwWatchCount * sizeof(HANDLE)); LPCM_CONNECTED_INFO pInfo = (LPCM_CONNECTED_INFO) CmMalloc(dwDataSize); // // Allocate the COPYDATASTRUCT // COPYDATASTRUCT *pCopyData = (COPYDATASTRUCT*) CmMalloc(sizeof(COPYDATASTRUCT)); if (NULL == pInfo || NULL == pCopyData) { lRes = ERROR_NOT_ENOUGH_MEMORY; } else { // // Fill in the CONNECTED_INFO // lstrcpyU(pInfo->szEntryName, pArgs->szServiceName); lstrcpyU(pInfo->szProfilePath, pArgs->piniProfile->GetFile()); // // Provide any password data that we have // lstrcpynU(pInfo->szPassword, pArgs->szPassword, sizeof(pInfo->szPassword)/sizeof(pInfo->szPassword[0])); lstrcpynU(pInfo->szUserName, pArgs->szUserName, sizeof(pInfo->szUserName)/sizeof(pInfo->szUserName[0])); lstrcpynU(pInfo->szInetPassword, pArgs->szInetPassword, sizeof(pInfo->szInetPassword)/sizeof(pInfo->szInetPassword[0])); // // And the RAS phonebook // if (pArgs->pszRasPbk) { lstrcpynU(pInfo->szRasPhoneBook, pArgs->pszRasPbk, sizeof(pInfo->szRasPhoneBook)/sizeof(pInfo->szRasPhoneBook[0])); } else { pInfo->szRasPhoneBook[0] = L'\0'; } pInfo->dwCmFlags = pArgs->dwFlags; // // Need to know about global creds for Fast User Switching // if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { pInfo->dwCmFlags |= FL_GLOBALCREDS; CMTRACE(TEXT("ConnectMonitor - we have globalcreds!!")); } // // For W95, we must pass initial statistics data to CMMON // pInfo->dwInitBytesRecv = -1; // default to no stats pInfo->dwInitBytesSend = -1; // default to no stats if (pArgs->pConnStatistics) { // // Get reg based stat data if available // if (pArgs->pConnStatistics->IsAvailable()) { pInfo->dwInitBytesRecv = pArgs->pConnStatistics->GetInitBytesRead(); pInfo->dwInitBytesSend = pArgs->pConnStatistics->GetInitBytesWrite(); } // // Note: Adapter info is good, even if stats aren't available // pInfo->fDialup2 = pArgs->pConnStatistics->IsDialupTwo(); } // // Update the watch process list at the end of the CONNECTED_INFO struct // if (dwWatchCount) { if (FALSE == SetWatchHandles(pArgs->phWatchProcesses, &pInfo->ahWatchHandles[0], hwndMon)) { pInfo->ahWatchHandles[0] = NULL; } } // // Send CONNECTED_INFO to CMMON // pCopyData->dwData = CMMON_CONNECTED_INFO; pCopyData->cbData = dwDataSize; pCopyData->lpData = (PVOID) pInfo; SendMessageU(hwndMon, WM_COPYDATA, NULL, (LPARAM) pCopyData); } // // Release allocations // if (pInfo) { CmFree(pInfo); } if (pCopyData) { CmFree(pCopyData); } } return HRESULT_FROM_WIN32(lRes); } //+---------------------------------------------------------------------------- // // Function: CreateConnTable // // Synopsis: Initializes our CConnectionTable ptr and creates a new ConnTable // or opens an existing one as needed // // Arguments: ArgsStruct *pArgs - Ptr to global args struct containing. // // Returns: HRESULT - Failure code // // History: nickball Created 2/9/98 // //+---------------------------------------------------------------------------- HRESULT CreateConnTable(ArgsStruct *pArgs) { HRESULT hrRet = E_FAIL; pArgs->pConnTable = new CConnectionTable(); if (pArgs->pConnTable) { // // We have our class, now create/open the connection table. // hrRet = pArgs->pConnTable->Open(); if (FAILED(hrRet)) { hrRet = pArgs->pConnTable->Create(); if (HRESULT_CODE(hrRet) == ERROR_ALREADY_EXISTS) { CMTRACE1(TEXT("CreateConnTable -- ConnTable creation failed with error 0x%x. Strange since the Open failed too..."), hrRet); } else { CMTRACE1(TEXT("CreateConnTable -- ConnTable creation failed with error 0x%x"), hrRet); } } } else { hrRet = HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY); } MYDBGASSERT(SUCCEEDED(hrRet)); return hrRet; } #if 0 // NT 301988 /* //+---------------------------------------------------------------------------- // // Function: HandleMainConnectRequest // // Synopsis: Helper routine to handle the possibility that there may be a // connect in progress on this service. // // Arguments: HWND hwndDlg - HWND of main dialog // ArgsStruct *pArgs - Ptr to global Args struct // // Returns: BOOL - TRUE if we have fully handled the request // and it is ok to terminate this instance. // // History: nickball Created 2/23/98 // //+---------------------------------------------------------------------------- BOOL HandleMainConnectRequest(HWND hwndDlg, ArgsStruct *pArgs) { MYDBGASSERT(pArgs); BOOL fResolved = FALSE; LPCM_CONNECTION pConnection = GetConnection(pArgs); // // If no conection found, then there is no work to be done here, continue. // if (pConnection) { // // If we are in any state besides RECONNECT, we can handle it here // if (CM_RECONNECTPROMPT != pConnection->CmState) { fResolved = TRUE; if (pArgs->dwFlags & FL_DESKTOP) { // // Caller is from the desktop, notify the user and we're done // NotifyUserOfExistingConnection(hwndDlg, pConnection, TRUE); } else { BOOL fSuccess = TRUE; // // We have a programmatic caller, if connected just bump the ref count // and return successfully. Otherwise we return failure so that the // caller doesn't erroneously believe that there is a connection. // if (CM_CONNECTED != pConnection->CmState) { fSuccess = FALSE; } else { UpdateTable(pArgs, CM_CONNECTING); } // // Terminate this connect instance. // EndMainDialog(hwndDlg, pArgs, 0); // fSuccess); } } else { // // We're in reconnect mode and going to connect. // if (!(pArgs->dwFlags & FL_RECONNECT)) { // // This request is not a reconnect request from CMMON, // make that sure the dialog is no longer displayed. // HangupNotifyCmMon(pArgs->pConnTable, pConnection->szEntry); } else { // // We are handling a reconnect for CMMON, reduce the usage // count so it is in sync when we begin connecting. // pArgs->pConnTable->RemoveEntry(pConnection->szEntry); } } CmFree(pConnection); } return fResolved; } */ #endif // // OnMainConnect: Command Handler when user clicked on 'Connect' Button in // Main Dialog Box // void OnMainConnect(HWND hwndDlg, ArgsStruct *pArgs) { CM_SET_TIMING_INTERVAL("OnMainConnect - Begin"); // // If we aren't ready to dial, set focus appropriately and bail // UINT nCtrlFocus; if (FALSE == CheckConnect(hwndDlg, pArgs, &nCtrlFocus, TRUE)) { MainSetDefaultButton(hwndDlg, nCtrlFocus); SetFocus(GetDlgItem(hwndDlg, nCtrlFocus)); return; } (void) InterlockedExchange(&(pArgs->lInConnectOrCancel), NOT_IN_CONNECT_OR_CANCEL); // // Access Points - Disable AP combo box before connecting // EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_ACCESSPOINT_STATIC),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_ACCESSPOINT_COMBO),FALSE); // // Store the current access point to reg. // if (pArgs->fAccessPointsEnabled) { WriteUserInfoToReg(pArgs, UD_ID_CURRENTACCESSPOINT, (PVOID)(pArgs->pszCurrentAccessPoint)); } // // Assume success unless something contradictory happens // pArgs->dwExitCode = ERROR_SUCCESS; HCURSOR hPrev = SetCursor(LoadCursorU(NULL,IDC_WAIT)); LPTSTR pszMsg = CmFmtMsg(g_hInst, IDMSG_WORKING); if (pszMsg) { SetDlgItemTextA(hwndDlg, IDC_MAIN_STATUS_DISPLAY, ""); AppendStatusPane(hwndDlg,pszMsg); CmFree(pszMsg); } // // We're connecting, update the table. // UpdateTable(pArgs, CM_CONNECTING); // // Clear out everything on the status panel // SetDlgItemTextA(hwndDlg, IDC_MAIN_STATUS_DISPLAY, ""); // // Set the default button to Cancel // SendMessageU(hwndDlg, DM_SETDEFID, (WPARAM)IDCANCEL, 0); SetFocus(GetDlgItem(hwndDlg,IDCANCEL)); BOOL fSaveUPD = TRUE; BOOL fSaveOtherUserInfo = TRUE; // // We want to save and/or delete credentials only when the user is logged on. // This is taken care of by the functions that get called here. As long as // the user is logged on, we try to mark, delete credentials and // potentially resave credential info. From this level we shouldn't // worry if we have the ras cred store or how the creds are really stored. // if (CM_LOGON_TYPE_USER == pArgs->dwWinLogonType) { // // If this is NT4 or Win9X the GetAndStoreUserInfo takes care of storing // the user info w/o the credential store. // if (OS_NT5) { // // For Win2K+ we use the RAS API to save the credentials. The call saves // and deletes user and global creds based on the current state and the // user's choices (whether to save a password, etc.) // TryToDeleteAndSaveCredentials(pArgs, hwndDlg); // // Parameter to GetAndStoreUserInfo() - doesn't save Username, Password, Domain // fSaveUPD = FALSE; } } else { // // User isn't logged on, thus we don't want to save anything // fSaveUPD = FALSE; fSaveOtherUserInfo = FALSE; } // // Gets the userinfo from the edit boxes into the pArgs structure ans saves the other // user flags. This is also saves the credentials on NT4 & Win 9x if the 3rd parameter is true // // 3rd parameter (fSaveUPD) - used to save Username, Domain, Password. // 4th param (fSaveOtherUserInfo) - used to save user info flags. (remember password, // dial automatically, etc.) // GetAndStoreUserInfo(pArgs, hwndDlg, fSaveUPD, fSaveOtherUserInfo); // // Vars for RAS // pArgs->nDialIdx = 0; // // Set our redial counter with the maximum. The max value is read // in when we initialize the dialog. It is just a place holder // nRedialCnt is the var used/modified to regulate the re-dial process. // pArgs->nRedialCnt = pArgs->nMaxRedials; // // Disable username controls before dialing // EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_USERNAME_EDIT),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_USERNAME_STATIC),FALSE); // // Disable password controls before dialing // EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_PASSWORD_EDIT),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_PASSWORD_STATIC),FALSE); // // Disable domain controls before dialing // EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_DOMAIN_EDIT),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_DOMAIN_STATIC),FALSE); // // disable all other buttons // EnableWindow(GetDlgItem(hwndDlg,IDOK),FALSE); EnableWindow(GetDlgItem(hwndDlg,IDC_MAIN_PROPERTIES_BUTTON),FALSE); if (pArgs->hwndResetPasswdButton) { EnableWindow(pArgs->hwndResetPasswdButton, FALSE); } if (!pArgs->fHideRememberPassword) { EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPASSWORD_CHECKBOX), FALSE); if (pArgs->fGlobalCredentialsSupported) { // // Also disable the option buttons // EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_SINGLE_USER), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_ALL_USER), FALSE); } } if (!pArgs->fHideDialAutomatically) { EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), FALSE); } // // Try to check the Advanced Tab settings (ICF/ICS) and see if we need to enable or disable // them based on what's configured in the .cms file. This is only on WinXP+ & if the user is logged in // VerifyAdvancedTabSettings(pArgs); // // Dial the number // DWORD dwResult = ERROR_SUCCESS; pArgs->Log.Log(PRECONNECT_EVENT, pArgs->GetTypeOfConnection()); // // Run the Pre-Connect actions // CActionList PreConnActList; PreConnActList.Append(pArgs->piniService, c_pszCmSectionPreConnect); if (!PreConnActList.RunAccordType(hwndDlg, pArgs)) { // // Connect action failed // UpdateTable(pArgs, CM_DISCONNECTED); dwResult = ERROR_INVALID_DLL; // Only used for failed CA } else { if (pArgs->IsDirectConnect()) { MYDBGASSERT(pArgs->hrcRasConn == NULL); pArgs->fUseTunneling = TRUE; pArgs->psState = PS_TunnelDialing; pArgs->dwStateStartTime = GetTickCount(); pArgs->nLastSecondsDisplay = (UINT) -1; dwResult = DoTunnelDial(hwndDlg,pArgs); } else { // // If the DynamicPhoneNumber flag is set, then we need to re-read // the phoneinfo from the profile and make sure it re-munged. // BOOL bDynamicNum = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmDynamicPhoneNumber); if (bDynamicNum) { LoadPhoneInfoFromProfile(pArgs); } // // Load dial info(phone #'s, etc) // In the auto-dial case we pass FALSE for fInstallModem so that // LoadDialInfo does not try to install a modem because it would // require user intervention // dwResult = LoadDialInfo(pArgs, hwndDlg, !(pArgs->dwFlags & FL_UNATTENDED), bDynamicNum); // // Close TAPI before we dial, this will be cleaned up when we unlink, // but there is no reason to keep TAPI tied up while we're dialing. // CloseTapi(&pArgs->tlsTapiLink); if (dwResult == ERROR_SUCCESS) { dwResult = DoRasDial(hwndDlg,pArgs,pArgs->nDialIdx); } // // If modem is not installed and LoadDialInfo failed to install modem, dwResult will be // ERROR_PORT_NOT_AVAILABLE. Ideally, we should disable the connect button and display // a different error message. // } } if (ERROR_SUCCESS != dwResult) { HangupCM(pArgs, hwndDlg); UpdateError(pArgs, dwResult); if (IsLogonAsSystem() && BAD_SCARD_PIN(dwResult)) { // // Disable the Connect button to avoid smartcard lockout. Also propagate // the error back to our caller (RAS) so that they can End the 'choose // connectoid' dialog and return to winlogon, where the user can enter // the correct PIN. // pArgs->dwSCardErr = dwResult; EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE); SendMessageU(hwndDlg, DM_SETDEFID, (WPARAM)IDCANCEL, 0); SetFocus(GetDlgItem(hwndDlg, IDCANCEL)); } SetLastError(dwResult); } SetCursor(hPrev); CM_SET_TIMING_INTERVAL("OnMainConnect - End"); } //+--------------------------------------------------------------------------- // // Function: UseTunneling // // Synopsis: Check to see if we should do tunneling based on fTunnelPrimary // and fTunnelReferences. // // Arguments: pArgs [the ArgStruct ptr] // dwEntry [the phone index] // // Returns: TRUE if we tunnel, FALSE otherwise. // // History: henryt Created 3/5/97 // //---------------------------------------------------------------------------- BOOL UseTunneling( ArgsStruct *pArgs, DWORD dwEntry ) { LPTSTR pszRefPhoneSource = NULL; BOOL fPhoneNumIsFromPrimaryPBK; LPTSTR pszTmp; CIni iniTmp(pArgs->piniProfile->GetHInst(),pArgs->piniProfile->GetFile(), pArgs->piniProfile->GetRegPath()); BOOL fUseTunneling = FALSE; // // Set the read flags // if (pArgs->dwGlobalUserInfo & CM_GLOBAL_USER_INFO_READ_ICS_DATA) { LPTSTR pszICSDataReg = BuildICSDataInfoSubKey(pArgs->szServiceName); if (pszICSDataReg) { iniTmp.SetReadICSData(TRUE); iniTmp.SetICSDataPath(pszICSDataReg); } CmFree(pszICSDataReg); } iniTmp.SetEntryFromIdx(dwEntry); pszRefPhoneSource = iniTmp.GPPS(c_pszCmSection, c_pszCmEntryPhoneSourcePrefix); // // If PhoneSource[0|1] is not empty, verify its existence // if (*pszRefPhoneSource) { // // pszRefPhoneSource is either a relative or full path. // CmConvertRelativePath() will do the conversion to a full path properly // pszTmp = CmConvertRelativePath(pArgs->piniService->GetFile(), pszRefPhoneSource); if (!pszTmp || FALSE == FileExists(pszTmp)) { CmFree(pszRefPhoneSource); CmFree(pszTmp); return fUseTunneling; } // // Is the phone # from the primary(top level) phone book? // fPhoneNumIsFromPrimaryPBK = (lstrcmpiU(pszTmp, pArgs->piniService->GetFile()) == 0); CmFree(pszTmp); fUseTunneling = ((fPhoneNumIsFromPrimaryPBK && pArgs->fTunnelPrimary) || (!fPhoneNumIsFromPrimaryPBK && pArgs->fTunnelReferences)); } else { // the phone # is not from a phone book. the user probably typed it in // him/herself. fUseTunneling = pArgs->fTunnelPrimary; } CmFree(pszRefPhoneSource); return fUseTunneling; } // // OnMainProperties: command handler for 'Properties' button in the main dialog box // int OnMainProperties(HWND hwndDlg, ArgsStruct *pArgs) { CMTRACE(TEXT("Begin OnMainProperties()")); // // do the settings dlg. // BOOL bCachedAccessPointsEnabled = pArgs->fAccessPointsEnabled; int iRet = DoPropertiesPropSheets(hwndDlg, pArgs); // // We need to re-enumerate the access points and re-check connecting because // the user may have added or deleted an access point and then hit cancel. // if (pArgs->hwndMainDlg) { if (bCachedAccessPointsEnabled != pArgs->fAccessPointsEnabled) { CMTRACE(TEXT("Access points state changed, returning to the main dialog which needs to relaunch itself with the proper template.")); iRet = ID_OK_RELAUNCH_MAIN_DLG; } else { // // If the user canceled, then we want to set the accesspoint back to what it was on the main dialog // since the user may have changed it on the properties dialog but then canceled. // if (pArgs->fAccessPointsEnabled) { if (0 == iRet) // user hit cancel { ChangedAccessPoint(pArgs, hwndDlg, IDC_MAIN_ACCESSPOINT_COMBO); } ShowAccessPointInfoFromReg(pArgs, hwndDlg, IDC_MAIN_ACCESSPOINT_COMBO); } UINT nCtrlFocus; CheckConnect(hwndDlg,pArgs,&nCtrlFocus); MainSetDefaultButton(hwndDlg,nCtrlFocus); SetFocus(GetDlgItem(hwndDlg,nCtrlFocus)); } } CMTRACE(TEXT("End OnMainProperties()")); return iRet; } // // user pressed the cancel button!!!!! // void OnMainCancel(HWND hwndDlg, ArgsStruct *pArgs) { CMTRACE1(TEXT("OnMainCancel(), state is %d"), pArgs->psState); // // Re-entrancy protection. If we're in the middle of a RasDial, wait 2 seconds. // If the "semaphore" is still held, exit. (This is only likely to happen during // a stress situation, so failing the cancel is acceptable.) // LONG lInConnectOrCancel; int SleepTimeInMilliseconds = 0; do { lInConnectOrCancel = InterlockedExchange(&(pArgs->lInConnectOrCancel), IN_CONNECT_OR_CANCEL); CMASSERTMSG(((NOT_IN_CONNECT_OR_CANCEL == lInConnectOrCancel) || (IN_CONNECT_OR_CANCEL == lInConnectOrCancel)), TEXT("OnMainCancel - synch variable has unexpected value!")); Sleep(50); SleepTimeInMilliseconds += 50; } while ((IN_CONNECT_OR_CANCEL == lInConnectOrCancel) && (SleepTimeInMilliseconds < 2000)); if (IN_CONNECT_OR_CANCEL == lInConnectOrCancel) { CMTRACE(TEXT("OnMainCancel - waited 2 seconds for system for InRasDial mutex to be freed, leaving Cancel")); return; } // // Terminate Lana // if (PS_TunnelDialing == pArgs->psState && pArgs->uLanaMsgId) { MYDBGASSERT(OS_W9X); PostMessageU(hwndDlg, pArgs->uLanaMsgId, 0, 0); } if (pArgs->psState != PS_Interactive && pArgs->psState != PS_Error) { pArgs->Log.Log(ONCANCEL_EVENT); // // Run OnCancel connect actions. If we are dialing, this is a cancel // dialing event. Note: The assumption here is CM never post itself // an IDCANCEL message when dialing // CActionList OnCancelActList; OnCancelActList.Append(pArgs->piniService, c_pszCmSectionOnCancel); // // fStatusMsgOnFailure = FALSE // OnCancelActList.RunAccordType(hwndDlg, pArgs, FALSE); } switch (pArgs->psState) { case PS_Dialing: case PS_TunnelDialing: case PS_Authenticating: case PS_TunnelAuthenticating: // fall through case PS_Pausing: // // we should also try to hangup for ps_pausing since cm could be // in the middle or redialing the tunnel server. we need to // hangup the first ppp connection. // // // Set fWaitForComplete to TRUE. // This will cause HangupCM to block until the ras handle is invalid. // Otherwise, HangupCM will return while the device is in use. // HangupCM(pArgs,hwndDlg, TRUE); // fWaitForComplete = TRUE // // Display cancelled message // AppendStatusPane(hwndDlg, IDMSG_CANCELED); SetInteractive(hwndDlg,pArgs); break; case PS_Online: // // If pArgs->fUseTunneling is TRUE, CM actually does not have the PS_Online state // MYDBGASSERT(!pArgs->fUseTunneling); if (pArgs->fUseTunneling) { break; } case PS_TunnelOnline: { TCHAR szTmp[MAX_PATH]; MYVERIFY(GetModuleFileNameU(g_hInst, szTmp, MAX_PATH)); pArgs->Log.Log(DISCONNECT_EVENT, szTmp); CActionList DisconnectActList; DisconnectActList.Append(pArgs->piniService, c_pszCmSectionOnDisconnect); // // fStatusMsgOnFailure = FALSE // DisconnectActList.RunAccordType(hwndDlg, pArgs, FALSE); HangupCM(pArgs,hwndDlg); pArgs->dwExitCode = ERROR_CANCELLED; // fall through } case PS_Error: case PS_Interactive: pArgs->dwExitCode = ERROR_CANCELLED; EndMainDialog(hwndDlg, pArgs, 0); // FALSE); break; default: MYDBGASSERT(FALSE); break; } // // We're definitely not waiting for a callback anymore. // pArgs->fWaitingForCallback = FALSE; // // We are exiting Cancel state // (void)InterlockedExchange(&(pArgs->lInConnectOrCancel), NOT_IN_CONNECT_OR_CANCEL); } void OnMainEnChange(HWND hwndDlg, ArgsStruct *pArgs) { CheckConnect(hwndDlg, pArgs, NULL); } //+---------------------------------------------------------------------------- // // Function: OnRasErrorMessage // // Synopsis: Process RAS error message // // Arguments: HWND hwndDlg - Main Dialog window handle // ArgsStruct *pArgs - // DWORD dwError - RAS error code // // Returns: Nothing // // History: fengsun Created Header 10/24/97 // //+---------------------------------------------------------------------------- void OnRasErrorMessage(HWND hwndDlg, ArgsStruct *pArgs, DWORD dwError) { // // Save off whether we are tunneling, before we change state // BOOL bTunneling = IsDialingTunnel(pArgs); // // Set the progstate to Error if user did not cancel dialing. // Note: Set here to ensure that we don't inadvertantly update the status on // timer ticks thereby overwriting the error message. Additionally we do this // following SetInteractive in the no-redial case below. // if (ERROR_CANCELLED != dwError) { CMTRACE(TEXT("OnRasErrorMessage - Entering PS_Error state")); pArgs->psState = PS_Error; } // // Set the "ErrorCode" property // pArgs->dwExitCode = dwError; lstrcpyU(pArgs->szLastErrorSrc, TEXT("RAS")); pArgs->Log.Log(ONERROR_EVENT, pArgs->dwExitCode, pArgs->szLastErrorSrc); // // Run On-Error connect actions // CActionList OnErrorActList; OnErrorActList.Append(pArgs->piniService, c_pszCmSectionOnError); // // fStatusMsgOnFailure = FALSE // OnErrorActList.RunAccordType(hwndDlg, pArgs, FALSE); LPTSTR pszRasErrMsg = NULL; // // See if the error is recoverable (re-dialable) // CheckConnectionError also display error msg in the status window // Get the ras err msg also. we'll display it ourself. // BOOL bDoRedial = !CheckConnectionError(hwndDlg, dwError, pArgs, bTunneling, &pszRasErrMsg); // // Whether CM get ERROR_PORT_NOT_AVAILABLE because of modem change // BOOL fNewModem = FALSE; if (dwError == ERROR_PORT_NOT_AVAILABLE && !IsDialingTunnel(pArgs)) { // // Modem is not avaliable. See if the modem is changed // BOOL fSameModem = TRUE; if (PickModem(pArgs, pArgs->szDeviceType, pArgs->szDeviceName, &fSameModem)) { if (!fSameModem) { // // If the modem is changed, use the new modem. // bDoRedial is still FALSE here so we will not // increase redial count or use the backup number // fNewModem = TRUE; } } // // if PickModem failed, do not try to install modem here // cnetcfg return ERROR_CANCELLED, even if modem is intalled // } // // should we try another tunnel dns addr? // BOOL fTryAnotherTunnelDnsAddr = FALSE; if (bDoRedial) { // // The error is recoverable // CMTRACE1(TEXT("OnRasErrorMessage - Recoverable error %u received."), dwError); // // If we're dialing a tunnel, try a different IP address on failure. // if (PS_TunnelDialing == pArgs->psState) { fTryAnotherTunnelDnsAddr = TryAnotherTunnelDnsAddress(pArgs); } // // If we're trying a different IP, then don't count this as a normal // redial. Otherwise, bump the indices and move on to the next number. if (!fTryAnotherTunnelDnsAddr) { // // we display the ras error only if: // (1) we're not redialing OR // (2) we're not redialing a tunnel OR // (3) we're redialing a tunnel but NOT redialing with a different // tunnel dns ip addr. // if (pszRasErrMsg) { AppendStatusPane(hwndDlg, pszRasErrMsg); } // should we redial? // if (pArgs->nRedialCnt) { // // We have not reached the retry limit, try to redial // pArgs->nRedialCnt--; pArgs->nDialIdx++; // // If ndx now matches count, or if the next number is empty // (not dialable) this our last number to dial on this pass. // Adjust the re-dial counter if it applies. // if (pArgs->nDialIdx == MAX_PHONE_NUMBERS || !pArgs->aDialInfo[pArgs->nDialIdx].szDialablePhoneNumber[0]) { pArgs->nDialIdx = 0; } } else { // // Last redial try failed // bDoRedial = FALSE; } } } else { CMTRACE1(TEXT("OnRasErrorMessage - Non-recoverable error %u received."), dwError); // // we display the ras error only if: // (1) we're not redialing OR // (2) we're not redialing a tunnel OR // (3) we're redialing a tunnel but NOT redialing with a different // tunnel dns ip addr. // if (pszRasErrMsg) { AppendStatusPane(hwndDlg, pszRasErrMsg); } } bDoRedial |= fNewModem; // fNewModem only true if not dialing tunnel // // Perform Hangup here // if (IsDialingTunnel(pArgs) && bDoRedial) { // // For tunnel dialing, only hangup tunnel connection, Do not hangup // PPP connection before retry. // MyRasHangup(pArgs,pArgs->hrcTunnelConn); pArgs->hrcTunnelConn = NULL; if (pArgs->IsDirectConnect()) { // // The statistic is stopped in HangupCM // Since we do not call HangupCM, we have to close it here // if (pArgs->pConnStatistics) { pArgs->pConnStatistics->Close(); } } } else { if (OS_NT) { HangupCM(pArgs, hwndDlg, FALSE, !bDoRedial); } else { // // On win9x, in some PPP case, when CM get Tunnel RAS error message, // RasHangup will not release the PPP RAS handle until this // message returns. See bug 39718 // PostMessageU(hwndDlg, WM_HANGUP_CM, !bDoRedial, dwError); } } // // If we want re-dial enter pause state, otherwise just SetInteractive // if (bDoRedial) { // // If the state is PS_Error, we will use the timer we set before the call. // However we will not check whether the timer expired here. // if (fTryAnotherTunnelDnsAddr) { // // if we want to try another tunnel dns addr, we don't want to display // any error msg or pause, just retry with another addr without the // user realizing it. // pArgs->dwStateStartTime = GetTickCount() + (pArgs->nRedialDelay * 1000); } else { // // NT #360488 - nickball // // Reset the timer so that we pause for the redial delay before // trying to connect again. ErrorEx (now unused), conditioned this // code on the error state not being PS_Error, however, this was // broken when we started setting the state to PS_Error at the // beginning of this function. Because ErrorEx is not longer used, // we can restore the timer reset to all states. // pArgs->dwStateStartTime = GetTickCount(); pArgs->nLastSecondsDisplay = (UINT) -1; } pArgs->psState = PS_Pausing; } else { SetInteractive(hwndDlg,pArgs); if (ERROR_CANCELLED != dwError) { CMTRACE(TEXT("OnRasErrorMessage - Restoring PS_Error state")); pArgs->psState = PS_Error; } pArgs->dwExitCode = dwError; // in 'unattended dial' mode, exit ICM if (pArgs->dwFlags & FL_UNATTENDED) { PostMessageU(hwndDlg, WM_COMMAND, IDCANCEL, dwError); } } if (pszRasErrMsg) { CmFree(pszRasErrMsg); } } //+---------------------------------------------------------------------------- // // Function: OnRasNotificationMessage // // Synopsis: Message handler for RAS status/error messages. // // Arguments: HWND hwndDlg - Main Dialog window handle // ArgsStruct *pArgs - Ptr to global Args struct // WPARAM wParam - RAS status message // LPARAM lParam - RAS error message. ERROR_SUCCESS if none. // // Returns: Error code if applicable. // // History: nickball Created Header 05/19/99 // //+---------------------------------------------------------------------------- DWORD OnRasNotificationMessage(HWND hwndDlg, ArgsStruct *pArgs, WPARAM wParam, LPARAM lParam) { CMTRACE2(TEXT("OnRasNotificationMessage() wParam=%u, lParam=%u"), wParam, lParam); if (pArgs->fIgnoreTimerRasMsg) { CMTRACE(TEXT("OnRasNotificationMessage() ignoring Ras and Timer messages")); return ERROR_SUCCESS; } // // If we have an error notification from RAS, handle it. // if (ERROR_SUCCESS != lParam) { // // If 2nd subchannel on multilinked ISDN fails, default to single channel. // if (OS_NT5) { if ((pArgs->dwRasSubEntry > 1) && (CM_ISDN_MODE_DUALCHANNEL_FALLBACK == pArgs->dwIsdnDialMode)) { PostMessageU(hwndDlg, WM_CONNECTED_CM,0,0); return ERROR_SUCCESS; } } // // Skip PENDING notifications // if (PENDING == lParam) { CMTRACE(TEXT("OnRasNotificationMessage() Skipping PENDING notification.")); return ERROR_SUCCESS; } // // If we're already in the interactive or error state, then // ignore any subsequent error notifications from RAS. // // For example: RAS often sends a ERROR_USER_DISCONNECTION // notification when we call RasHangup. // if (pArgs->psState == PS_Interactive || pArgs->psState == PS_Error) { CMTRACE1(TEXT("OnRasNotificationMessage() Ignoring error because pArgs->psState is %u."), pArgs->psState); return ERROR_SUCCESS; } CMTRACE(TEXT("OnRasNotificationMessage() Handling error message.")); OnRasErrorMessage(hwndDlg, pArgs, (DWORD)lParam); } else { // We have a RAS status update, act accordingly switch (wParam) { case RASCS_Authenticate: CMTRACE(TEXT("RASCS_Authenticate")); if (IsDialingTunnel(pArgs)) // PPTP dialing pArgs->psState = PS_TunnelAuthenticating; else pArgs->psState = PS_Authenticating; pArgs->dwStateStartTime = GetTickCount(); pArgs->nLastSecondsDisplay = (UINT) -1; break; case RASCS_Connected: { CMTRACE(TEXT("RASCS_Connected")); // // Post a message to ourselves to indicate that we are connected // PostMessageU(hwndDlg, WM_CONNECTED_CM,0,0); break; } // // Pause states are dealt with explicity below // case (RASCS_PAUSED + 4): // 4100 - RASCS_InvokeEapUI case RASCS_Interactive: case RASCS_RetryAuthentication: case RASCS_CallbackSetByCaller: case RASCS_PasswordExpired: break; // // Callback handling states // case RASCS_PrepareForCallback: pArgs->fWaitingForCallback = TRUE; pArgs->psState = PS_Pausing; break; case RASCS_CallbackComplete: pArgs->fWaitingForCallback = FALSE; break; // // The following status codes are not handled explicitly // case RASCS_Disconnected: break; case RASCS_SubEntryConnected: break; case RASCS_SubEntryDisconnected: break; case RASCS_OpenPort: break; case RASCS_PortOpened: break; case RASCS_ConnectDevice: break; case RASCS_DeviceConnected: break; case RASCS_AllDevicesConnected: break; case RASCS_AuthNotify: break; case RASCS_AuthRetry: break; case RASCS_AuthCallback: break; case RASCS_AuthChangePassword: break; case RASCS_AuthProject: break; case RASCS_AuthLinkSpeed: break; case RASCS_AuthAck: break; case RASCS_ReAuthenticate: break; case RASCS_Authenticated: break; case RASCS_WaitForModemReset: break; case RASCS_WaitForCallback: break; case RASCS_Projected: break; case RASCS_StartAuthentication: break; case RASCS_LogonNetwork: break; default: CMTRACE(TEXT("OnRasNotificationMessage() - message defaulted")); break; } } if (wParam & RASCS_PAUSED) { // // Screen out unsupported states // switch (wParam) { case RASCS_Interactive: // for scripts -- NTRAID 378224 case (RASCS_PAUSED + 4): // 4100 - RASCS_InvokeEapUI case RASCS_PasswordExpired: case RASCS_RetryAuthentication: case RASCS_CallbackSetByCaller: PostMessageU(hwndDlg, WM_PAUSE_RASDIAL, wParam, lParam); break; default: MYDBGASSERT(FALSE); return (ERROR_INTERACTIVE_MODE); // unhandled pause state } } return ERROR_SUCCESS; } // timer: check the current connection manager status, update the status message // on the screen void OnMainTimer(HWND hwndDlg, ArgsStruct *pArgs) { // // If timer ID is null, don't process messages // if (NULL == pArgs->nTimerId) { return; } // // Timer is good, check StartupInfoLoad // LPTSTR pszMsg = NULL; DWORD dwSeconds = (GetTickCount() - pArgs->dwStateStartTime) / 1000; CheckStartupInfo(hwndDlg, pArgs); // CMTRACE1(TEXT("OnMainTimer() pArgs->psState is %u"), pArgs->psState); // // Update future splash if any // MapStateToFrame(pArgs); switch (pArgs->psState) { case PS_Dialing: if (pArgs->nLastSecondsDisplay != dwSeconds) { pszMsg = CmFmtMsg(g_hInst, IDMSG_DIALING, pArgs->aDialInfo[pArgs->nDialIdx].szDisplayablePhoneNumber, pArgs->szDeviceName, dwSeconds); // // Clear the status window // SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, TEXT("")); pArgs->nLastSecondsDisplay = (UINT) dwSeconds; } break; case PS_TunnelDialing: if (pArgs->nLastSecondsDisplay != dwSeconds) { pszMsg = CmFmtMsg(g_hInst, IDMSG_TUNNELDIALING, pArgs->GetTunnelAddress(), dwSeconds); // // Clear the status window // SetDlgItemText(hwndDlg, IDC_MAIN_STATUS_DISPLAY, TEXT("")); pArgs->nLastSecondsDisplay = (UINT) dwSeconds; } break; case PS_Pausing: // // Special case of pausing is when we're waiting for the server to call us back. // if (pArgs->fWaitingForCallback) { // // Notify the user of this fact // pszMsg = CmFmtMsg(g_hInst, IDMSG_WAITING_FOR_CALLBACK, (GetTickCount()-pArgs->dwStateStartTime)/1000); // // Clear the status window // SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, TEXT("")); pArgs->nLastSecondsDisplay = (UINT) dwSeconds; break; } if (GetTickCount()-pArgs->dwStateStartTime <= pArgs->nRedialDelay * 1000) { // // Update the display if not timeout // if (pArgs->nLastSecondsDisplay != dwSeconds) { pszMsg = CmFmtMsg(g_hInst,IDMSG_PAUSING,dwSeconds); pArgs->nLastSecondsDisplay = (UINT) dwSeconds; } } else { DWORD dwRes; if (pArgs->IsDirectConnect() || pArgs->hrcRasConn != NULL) { // // For the first tunnel try, CM does not hangup ppp connection // MYDBGASSERT(pArgs->fUseTunneling); pArgs->psState = PS_TunnelDialing; pArgs->dwStateStartTime = GetTickCount(); pArgs->nLastSecondsDisplay = (UINT) -1; dwRes = DoTunnelDial(hwndDlg,pArgs); // // Update the status right away because there are times // that things happen so quickly that the main status // display doesn't have a chance to display the tunnel // dialing info... // pszMsg = CmFmtMsg(g_hInst, IDMSG_TUNNELDIALING, pArgs->GetTunnelAddress(), 0); // // Clear the status window // SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, TEXT("")); } else { dwRes = DoRasDial(hwndDlg,pArgs,pArgs->nDialIdx); } if (dwRes == ERROR_SUCCESS) { MapStateToFrame(pArgs); pArgs->dwStateStartTime = GetTickCount(); pArgs->nLastSecondsDisplay = (UINT) -1; } else { HangupCM(pArgs, hwndDlg); UpdateError(pArgs, dwRes); SetLastError(dwRes); } } break; case PS_Authenticating: if (pArgs->nLastSecondsDisplay != dwSeconds) { // // Get the appropriate username based on whether we're // tunneling and using the same credentials for dial-up. // LPTSTR pszTmpUserName; if (pArgs->fUseTunneling && (!pArgs->fUseSameUserName)) { pszTmpUserName = pArgs->szInetUserName; } else { pszTmpUserName = pArgs->szUserName; } // // If username is still blank, use the RasDialParams as a // backup. This can occur in cases such as EAP // if (TEXT('\0') == *pszTmpUserName) { pszTmpUserName = pArgs->pRasDialParams->szUserName; } pszMsg = CmFmtMsg(g_hInst, IDMSG_CHECKINGPASSWORD, pszTmpUserName, (GetTickCount()-pArgs->dwStateStartTime)/1000); // // Clear the status window // SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, TEXT("")); pArgs->nLastSecondsDisplay = (UINT) dwSeconds; } break; case PS_TunnelAuthenticating: if (pArgs->nLastSecondsDisplay != dwSeconds) { LPTSTR pszTmpUserName = pArgs->szUserName; // // If username is still blank, use the RasDialParams as a // backup. This can occur in cases such as EAP // if (TEXT('\0') == *pszTmpUserName) { pszTmpUserName = pArgs->pRasDialParams->szUserName; } pszMsg = CmFmtMsg(g_hInst, IDMSG_CHECKINGPASSWORD, pszTmpUserName, (GetTickCount()-pArgs->dwStateStartTime)/1000); // // Clear the status window // SetDlgItemTextU(hwndDlg, IDC_MAIN_STATUS_DISPLAY, TEXT("")); pArgs->nLastSecondsDisplay = (UINT) dwSeconds; } break; case PS_Online: // // If pArgs->fUseTunneling is TRUE, CM actually does not have the PS_Online state // MYDBGASSERT(!pArgs->fUseTunneling); case PS_TunnelOnline: // // The dialog should be ended by now // MYDBGASSERT(!"The dialog should be ended by now"); break; case PS_Error: case PS_Interactive: default: break; } // If we have a status message as a result of the above, display it if (pszMsg) { AppendStatusPane(hwndDlg,pszMsg); CmFree(pszMsg); } } // // MainDlgProc: main dialog box message processing function // INT_PTR CALLBACK MainDlgProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { ArgsStruct *pArgs = (ArgsStruct *) GetWindowLongU(hwndDlg,DWLP_USER); static const DWORD adwHelp[] = {IDC_MAIN_NOPROMPT_CHECKBOX, IDH_LOGON_AUTOCONN, IDC_MAIN_NOPASSWORD_CHECKBOX, IDH_LOGON_SAVEPW, IDC_MAIN_USERNAME_STATIC,IDH_LOGON_NAME, IDC_MAIN_USERNAME_EDIT,IDH_LOGON_NAME, IDC_MAIN_PASSWORD_STATIC,IDH_LOGON_PSWD, IDC_MAIN_PASSWORD_EDIT,IDH_LOGON_PSWD, IDC_MAIN_DOMAIN_STATIC, IDH_LOGON_DOMAIN, IDC_MAIN_DOMAIN_EDIT, IDH_LOGON_DOMAIN, IDC_MAIN_RESET_PASSWORD, IDH_LOGON_NEW, IDC_MAIN_MESSAGE_DISPLAY,IDH_LOGON_SVCMSG, IDC_MAIN_STATUS_LABEL,IDH_LOGON_CONNECT_STAT, IDC_MAIN_STATUS_DISPLAY,IDH_LOGON_CONNECT_STAT, IDOK,IDH_LOGON_CONNECT, IDCANCEL,IDH_LOGON_CANCEL, IDC_MAIN_PROPERTIES_BUTTON,IDH_LOGON_PROPERTIES, IDC_MAIN_HELP_BUTTON,IDH_CMHELP, IDC_MAIN_ACCESSPOINT_COMBO, IDH_LOGON_ACCESSPOINTS, IDC_MAIN_ACCESSPOINT_STATIC, IDH_LOGON_ACCESSPOINTS, IDC_OPT_CREDS_SINGLE_USER, IDH_LOGON_SAVEFORME, IDC_OPT_CREDS_ALL_USER, IDH_LOGON_SAVEFORALL, 0,0}; // // Dialog box message processing // switch (uMsg) { case WM_PAINT: CheckStartupInfo(hwndDlg, pArgs); break; case WM_INITDIALOG: CM_SET_TIMING_INTERVAL("WM_INITDIALOG - Begin"); UpdateFont(hwndDlg); // // Extract args and perform main initialization // pArgs = (ArgsStruct *) lParam; if (pArgs) { pArgs->hwndMainDlg = hwndDlg; } SetWindowLongU(hwndDlg,DWLP_USER, (LONG_PTR) pArgs); OnMainInit(hwndDlg, pArgs); CM_SET_TIMING_INTERVAL("WM_INITDIALOG - End"); return (FALSE); case WM_ENDSESSION: // // Windows system is shutting down or logging off // if ((BOOL)wParam == TRUE) { // // Just cancel // OnMainCancel(hwndDlg, pArgs); } return 0; case WM_COMMAND: switch (LOWORD(wParam)) { case IDOK: OnMainConnect(hwndDlg,pArgs); // // Check if there is an error, and if it's unattended dial, // we just exit silently -- byao 5/9/97 // if ((PS_Interactive == pArgs->psState || PS_Error == pArgs->psState) && (pArgs->dwFlags & FL_UNATTENDED)) { OnMainCancel(hwndDlg, pArgs); } return (TRUE); case IDC_MAIN_PROPERTIES_BUTTON: if (ID_OK_RELAUNCH_MAIN_DLG == OnMainProperties(hwndDlg,pArgs)) { // // We want to relaunch the logon UI with Access Points enabled or disabled depending // on the change the user made in the properties dialog. // EndMainDialog(hwndDlg, pArgs, ID_OK_RELAUNCH_MAIN_DLG); } return (TRUE); case IDC_MAIN_HELP_BUTTON: { UINT nCtrlFocus = IsWindowEnabled(GetDlgItem(hwndDlg,IDOK)) ? IDOK : IDCANCEL; CmWinHelp(hwndDlg,hwndDlg,pArgs->pszHelpFile,HELP_FORCEFILE,0); MainSetDefaultButton(hwndDlg,nCtrlFocus); return (TRUE); } case IDC_MAIN_NOPROMPT_CHECKBOX: pArgs->fDialAutomatically = !pArgs->fDialAutomatically; if (TRUE == pArgs->fDialAutomatically) { MYDBGASSERT(!pArgs->fHideDialAutomatically); // // Display message explaining Dial Automatically // LPTSTR pszTmp = pArgs->piniService->GPPS(c_pszCmSection, c_pszCmEntryDialAutoMessage); if (pszTmp && *pszTmp) { MessageBoxEx(hwndDlg, pszTmp, pArgs->szServiceName, MB_OK|MB_ICONWARNING, LANG_USER_DEFAULT); } CmFree(pszTmp); } break; case IDC_MAIN_NOPASSWORD_CHECKBOX: pArgs->fRememberMainPassword = !(pArgs->fRememberMainPassword); if (!pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryPwdOptional)) { // // If password is not optional, enable/disable // Dial Automatically according to state of // "Remember password" // EnableWindow(GetDlgItem(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX), pArgs->fRememberMainPassword); if (FALSE == pArgs->fRememberMainPassword) { // // Reset Dial Automatically if user // unchecks Save Password and password // is not optional // CheckDlgButton(hwndDlg, IDC_MAIN_NOPROMPT_CHECKBOX, FALSE); pArgs->fDialAutomatically = FALSE; if (pArgs->fGlobalCredentialsSupported) { // // Also disable the option buttons // EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_SINGLE_USER), FALSE); EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_ALL_USER), FALSE); } // // Since we aren't remembering the main password // see if we need to not remember Inet passwords // if (pArgs->fUseSameUserName) { pArgs->fRememberInetPassword = FALSE; CmWipePassword(pArgs->szInetPassword); } // // If the password edit hasn't been edited by the user, then we // mostly likely have 16 *'s which doesn't help the user when // they try to connect. Thus we need to clear the edit box // HWND hwndPassword = GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT); if (hwndPassword) { pArgs->fIgnoreChangeNotification = TRUE; BOOL fPWFieldModified = (BOOL) SendMessageU(hwndPassword, EM_GETMODIFY, 0L, 0L); if (FALSE == fPWFieldModified) { CmWipePassword(pArgs->szPassword); SetDlgItemTextU(hwndDlg, IDC_MAIN_PASSWORD_EDIT, TEXT("")); } pArgs->fIgnoreChangeNotification = FALSE; } } else { // // Save Password option is Enabled // if (pArgs->fGlobalCredentialsSupported) { // // Also enable the option buttons // EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_SINGLE_USER), TRUE); EnableWindow(GetDlgItem(hwndDlg, IDC_OPT_CREDS_ALL_USER), TRUE); } HWND hwndPassword = GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT); if (hwndPassword) { BOOL fPWFieldModified = (BOOL) SendMessageU(hwndPassword, EM_GETMODIFY, 0L, 0L); if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { // // Try to reload current creds now that the user has enabled the save // password option, unless the password field has been edited // CheckDlgButton(hwndDlg, IDC_OPT_CREDS_ALL_USER, BST_CHECKED); CheckDlgButton(hwndDlg, IDC_OPT_CREDS_SINGLE_USER, BST_UNCHECKED); if (FALSE == fPWFieldModified) { // // Set the 3rd param to TRUE in order to bypass the check // that it's called when we are in the local credential mode. // SwitchToGlobalCreds(pArgs, hwndDlg, TRUE); } } else { if (pArgs->fGlobalCredentialsSupported) { CheckDlgButton(hwndDlg, IDC_OPT_CREDS_ALL_USER, BST_UNCHECKED); CheckDlgButton(hwndDlg, IDC_OPT_CREDS_SINGLE_USER, BST_CHECKED); } if (FALSE == fPWFieldModified) { // // Set the 3rd param to TRUE in order to bypass the check // that it's called when we are in the global credential mode. // SwitchToLocalCreds(pArgs, hwndDlg, TRUE); } } } } } break; case IDC_OPT_CREDS_SINGLE_USER: { // // FALSE - allows the function to only execute if we are currently using // the global credential store and the user now wants to switch. // SwitchToLocalCreds(pArgs, hwndDlg, FALSE); break; } case IDC_OPT_CREDS_ALL_USER: { // // FALSE - allows the function to only execute if we are currently using // the local credential store and the user now wants to switch. // SwitchToGlobalCreds(pArgs, hwndDlg, FALSE); break; } case IDC_MAIN_RESET_PASSWORD: OnResetPassword(hwndDlg, pArgs); break; case IDC_MAIN_CUSTOM: OnCustom(hwndDlg, pArgs); break; case IDCANCEL: OnMainCancel(hwndDlg,pArgs); return (TRUE); case IDC_MAIN_PASSWORD_EDIT: case IDC_MAIN_USERNAME_EDIT: case IDC_MAIN_DOMAIN_EDIT: if ((HIWORD(wParam) == EN_CHANGE)) { if (!pArgs->fIgnoreChangeNotification) { OnMainEnChange(hwndDlg,pArgs); return (TRUE); } } break; case IDC_MAIN_ACCESSPOINT_COMBO: if (CBN_SELENDOK == HIWORD(wParam)) { if (ChangedAccessPoint(pArgs, hwndDlg, IDC_MAIN_ACCESSPOINT_COMBO)) { UINT nCtrlFocus; CheckConnect(hwndDlg,pArgs,&nCtrlFocus); MainSetDefaultButton(hwndDlg,nCtrlFocus); } } default: break; } break; case WM_HELP: CmWinHelp((HWND) (((LPHELPINFO) lParam)->hItemHandle), (HWND) (((LPHELPINFO) lParam)->hItemHandle), pArgs->pszHelpFile, HELP_WM_HELP, (ULONG_PTR) (LPSTR) adwHelp); return (TRUE); case WM_CONTEXTMENU: { POINT pt = {LOWORD(lParam), HIWORD(lParam)}; HWND hwndCtrl; ScreenToClient(hwndDlg, &pt); hwndCtrl = ChildWindowFromPoint(hwndDlg, pt); if (!hwndCtrl || HaveContextHelp(hwndDlg, hwndCtrl)) { CmWinHelp((HWND) wParam, hwndCtrl, pArgs->pszHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)adwHelp); } return (TRUE); } case WM_SIZE: // // Dynamicly Enable/Disable system menu // { HMENU hMenu = GetSystemMenu(hwndDlg, FALSE); MYDBGASSERT(hMenu); // // if the dlg is minimized, then disable the minimized menu // if (wParam == SIZE_MINIMIZED) { EnableMenuItem(hMenu, SC_MINIMIZE, MF_BYCOMMAND | MF_GRAYED); EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_ENABLED); } else if (wParam != SIZE_MAXHIDE && wParam != SIZE_MAXSHOW) { EnableMenuItem(hMenu, SC_MINIMIZE, MF_BYCOMMAND | MF_ENABLED); EnableMenuItem(hMenu, SC_RESTORE, MF_BYCOMMAND | MF_GRAYED); } } break; case WM_TIMER: // // Ignore the timer, if a (pre)connect action is running // if (!pArgs->fIgnoreTimerRasMsg) { OnMainTimer(hwndDlg,pArgs); } break; case WM_PALETTEISCHANGING: CMTRACE2(TEXT("MainDlgProc() got WM_PALETTEISCHANGING message, wParam=0x%x, hwndDlg=0x%x."), wParam, hwndDlg); break; case WM_PALETTECHANGED: { // // If its not our window that changed the palette, and we have a bitmap // if (IsWindowVisible(hwndDlg) && (wParam != (WPARAM) hwndDlg) && pArgs->BmpData.hDIBitmap) { // // Handle the palette change. // // Note: We used to pass a flag indicating whether another // bitmap was being displayed, but given that we select the // paletted as a background app. this is no longer needed // CMTRACE2(TEXT("MainDlgProc() handling WM_PALETTECHANGED message, wParam=0x%x, hwndDlg=0x%x."), wParam, hwndDlg); PaletteChanged(&pArgs->BmpData, hwndDlg, IDC_MAIN_BITMAP); } return TRUE; } case WM_QUERYNEWPALETTE: if (IsWindowVisible(hwndDlg)) { CMTRACE2(TEXT("MainDlgProc() handling WM_QUERYNEWPALETTE message, wParam=0x%x, hwndDlg=0x%x."), wParam, hwndDlg); QueryNewPalette(&pArgs->BmpData, hwndDlg, IDC_MAIN_BITMAP); } return TRUE; case WM_LOADSTARTUPINFO: OnMainLoadStartupInfo(hwndDlg, pArgs); break; case WM_HANGUP_CM: MYDBGASSERT(OS_W9X); HangupCM(pArgs, hwndDlg, FALSE, (BOOL)wParam); break; case WM_CONNECTED_CM: OnConnectedCM(hwndDlg, pArgs); break; case WM_PAUSE_RASDIAL: OnPauseRasDial(hwndDlg, pArgs, wParam, lParam); break; default: break; } if (pArgs && (uMsg == pArgs->uMsgId)) { OnRasNotificationMessage(hwndDlg, pArgs, wParam, lParam); return (TRUE); } return (FALSE); } //+--------------------------------------------------------------------------- // // Function: ProcessCleanup // // Synopsis: Helper function to encapsulate closing Watch process handles // // Arguments: pArgs - pointer to global args struct // // Returns: Nothing // // History: a-nichb - Created - 4/30/97 // //---------------------------------------------------------------------------- void ProcessCleanup(ArgsStruct* pArgs) { BOOL bRes; if (pArgs->phWatchProcesses) { DWORD dwIdx; for (dwIdx=0;pArgs->phWatchProcesses[dwIdx];dwIdx++) { bRes = CloseHandle(pArgs->phWatchProcesses[dwIdx]); #ifdef DEBUG if (!bRes) { CMTRACE1(TEXT("ProcessCleanup() CloseHandle() failed, GLE=%u."), GetLastError()); } #endif } CmFree(pArgs->phWatchProcesses); } } //+--------------------------------------------------------------------------- // // Function: CheckProfileIntegrity // // Synopsis: Helper function to verify that we have valid profile. // Verifies that we have a .CMP file name and that the // .CMS file exists. // // Arguments: pArgs - pointer to global args struct // // Returns: TRUE if profile is valid // // History: a-nichb - Created - 5/8/97 // byao - Modified - 6/3/97 Added CMS/CMP file version check //---------------------------------------------------------------------------- BOOL CheckProfileIntegrity(ArgsStruct* pArgs) { LPTSTR pszTmp = NULL; LPCTSTR pszCmsFile = NULL; DWORD dwCmsVersion, dwCmpVersion, dwCmVersion; int iMsgId = 0; // // Make sure that we have a profile name and a CMS that exists // if (!(*pArgs->piniProfile->GetFile())) { iMsgId = IDMSG_DAMAGED_PROFILE; CMASSERTMSG(FALSE, TEXT("CheckProfileIntegrity() can't run without a .cmp file.")); } // // If profile is good, check CMS // if (0 == iMsgId) { pszCmsFile = pArgs->piniService->GetFile(); if (!*pszCmsFile || FALSE == FileExists(pszCmsFile)) { iMsgId = IDMSG_DAMAGED_PROFILE; CMASSERTMSG(FALSE, TEXT("CheckProfileIntegrity() can't run without a valid .cms file.")); } } // // Now check the CMS/CMP file version // if (0 == iMsgId) { dwCmsVersion = pArgs->piniService->GPPI(c_pszCmSectionProfileFormat, c_pszVersion); dwCmpVersion = pArgs->piniProfile->GPPI(c_pszCmSectionProfileFormat, c_pszVersion); if (dwCmsVersion != dwCmpVersion) { iMsgId = IDMSG_DAMAGED_PROFILE; CMASSERTMSG(FALSE, TEXT("CheckProfileIntegrity() can't run with different version numbers.")); } if (0 == iMsgId) { if (dwCmsVersion > PROFILEVERSION || dwCmpVersion > PROFILEVERSION) { // // CM has older version than either CMS or CMP file // iMsgId = IDMSG_WRONG_PROFILE_VERSION; CMASSERTMSG(FALSE, TEXT("CheckProfileIntegrity() can't run with a newer CMS/CMP file.")); } } } // // Report any problems to the user // if (iMsgId) { pszTmp = CmFmtMsg(g_hInst, iMsgId); MessageBoxEx(NULL, pszTmp, pArgs->szServiceName, MB_OK|MB_ICONSTOP, LANG_USER_DEFAULT);//13309 CmFree(pszTmp); pArgs->dwExitCode = ERROR_WRONG_INFO_SPECIFIED; return FALSE; } return TRUE; } //+---------------------------------------------------------------------------- // // Function: GetConnectType // // Synopsis: Encapsulates determination of connect type based upon tunneling, // etc. // // Arguments: ArgsStruct *pArgs - Ptr to global Args struct // // Returns: Nothing // // History: nickball Created 2/9/98 // //+---------------------------------------------------------------------------- void GetConnectType(ArgsStruct *pArgs) { // // If tunneling is not enabled, the decision is a simple one // if (!IsTunnelEnabled(pArgs)) { // // Only support dial-up, if tunnel is not enabled // pArgs->SetBothConnTypeSupported(FALSE); pArgs->SetDirectConnect(FALSE); } else { // // Load connection type info for CM 1.1, default is support both // int iSupportDialup = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryDialup, 1); int iSupportDirect = pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryDirect, 1); if (iSupportDialup == TRUE && iSupportDirect == TRUE) { pArgs->SetBothConnTypeSupported(TRUE); if (pArgs->piniBoth->GPPI(c_pszCmSection, c_pszCmEntryConnectionType, 0)) { pArgs->SetDirectConnect(TRUE); } else { pArgs->SetDirectConnect(FALSE); } } else { pArgs->SetBothConnTypeSupported(FALSE); pArgs->SetDirectConnect(iSupportDirect == TRUE); } } } //+---------------------------------------------------------------------------- // // Function: _ArgsStruct::GetTypeOfConnection // // Synopsis: Figures out what type of connection we are doing (dialup, // double dial, or direct) and returns one of the connection define // values listed in icm.h. // // Arguments: None // // Returns: DWORD - value indicating the type of connection, see icm.h for values // // History: quintinb Created 04/20/00 // //+---------------------------------------------------------------------------- DWORD _ArgsStruct::GetTypeOfConnection() { DWORD dwType = 0; if (this->IsDirectConnect()) { return DIRECT_CONNECTION; } else { // // Its not direct, so see if the primary phone // number is for a tunneling scenario. // if (this->fUseTunneling) // Ambiguous during Pre-Init action. { return DOUBLE_DIAL_CONNECTION; } else { return DIAL_UP_CONNECTION; } } } //+---------------------------------------------------------------------------- // // Function: _ArgsStruct::GetProperty // // Synopsis: get the cm property by name // This function is used by connect actions // // Arguments: const TCHAR* pszName - name of the property // BOOL *pbValidPropertyName - ptr to bool to indicate validity of property // // Returns: LPTSTR - Value of the property. Caller should use CmFree // to free the memory // // History: fengsun Created Header 07/07/98 // nickball pbValidPropertyName 07/27/99 // //+---------------------------------------------------------------------------- LPTSTR _ArgsStruct::GetProperty(const TCHAR* pszName, BOOL *pbValidPropertyName) { *pbValidPropertyName = TRUE; // // This function could be called with in RasCustomHangup. // Some information of pArgs may bot be loaded // MYDBGASSERT(pszName); MYDBGASSERT(pszName[0]); if (pszName == NULL) { return NULL; } // // Type - Dial-up only, VPN only, double-dial // if (lstrcmpiU(pszName, TEXT("ConnectionType")) == 0) { LPTSTR pszValue = (LPTSTR)CmMalloc(64*sizeof(TCHAR)); // large enough to hold the error code MYDBGASSERT(pszValue); if (pszValue) { wsprintfU(pszValue, TEXT("%u"), this->GetTypeOfConnection()); } return pszValue; } // // UserPrefix // if (lstrcmpiU(pszName,TEXT("UserPrefix")) == 0) { LPTSTR pszUsernamePrefix = NULL; LPTSTR pszUsernameSuffix = NULL; // // Retrieve the suffix and prefix as they are a logical pair, // but we only return the allocated PREFIX in this case. // CIni *piniService = GetAppropriateIniService(this, this->nDialIdx); GetPrefixSuffix(this, piniService, &pszUsernamePrefix, &pszUsernameSuffix); CmFree(pszUsernameSuffix); delete piniService; return pszUsernamePrefix; } // // UserSuffix // if (lstrcmpiU(pszName,TEXT("UserSuffix")) == 0) { LPTSTR pszUsernamePrefix = NULL; LPTSTR pszUsernameSuffix = NULL; // // Retrieve the suffix and prefix as they are a logical pair, // but we only return the allocated SUFFIX in this case. // CIni *piniService = GetAppropriateIniService(this, this->nDialIdx); GetPrefixSuffix(this, piniService, &pszUsernamePrefix, &pszUsernameSuffix); CmFree(pszUsernamePrefix); delete piniService; return pszUsernameSuffix; } // // UserName // if (lstrcmpiU(pszName,TEXT("UserName")) == 0) { LPTSTR pszValue = NULL; // // We want to get the value by calling GetUserInfo so that we don't break // existing scenarios. Otherwise for Winlogon and ICS case we'll just take the // value directly out of the Args Structure. // if (CM_LOGON_TYPE_USER == this->dwWinLogonType) { GetUserInfo(this, UD_ID_USERNAME, (PVOID*)&pszValue); } else { pszValue = CmStrCpyAlloc(this->szUserName); } return pszValue; } // // InetUserName // if (lstrcmpiU(pszName,TEXT("InetUserName")) == 0) { LPTSTR pszValue = NULL; // // If we aren't doing a double dial, then the InetUserName doesn't make // sense and thus should be zero. Also if UseSameUserName is // set then we want to return the UserName and skip trying to // find the InetUserName // if (this->fUseTunneling && (FALSE == this->IsDirectConnect())) { if (this->piniService->GPPB(c_pszCmSection, c_pszCmEntryUseSameUserName)) { // // We want to get the value by calling GetUserInfo so that we don't break // existing scenarios. Otherwise for Winlogon and ICS case we'll just take the // value directly out of the Args Structure. // if (CM_LOGON_TYPE_USER == this->dwWinLogonType) { GetUserInfo(this, UD_ID_USERNAME, (PVOID*)&pszValue); } else { pszValue = CmStrCpyAlloc(this->szUserName); } } else { // // We want to get the value by calling GetUserInfo so that we don't break // existing scenarios. Otherwise for Winlogon and ICS case we'll just take the // value directly out of the Args Structure. // if (CM_LOGON_TYPE_USER == this->dwWinLogonType) { GetUserInfo(this, UD_ID_INET_USERNAME, (PVOID*)&pszValue); } else { pszValue = CmStrCpyAlloc(this->szInetUserName); } } } return pszValue; } // // Domain // if (lstrcmpiU(pszName,TEXT("Domain")) == 0) { LPTSTR pszValue = NULL; // // We want to get the value by calling GetUserInfo so that we don't break // existing scenarios. Otherwise for Winlogon and ICS case we'll just take the // value directly out of the Args Structure. // if (CM_LOGON_TYPE_USER == this->dwWinLogonType) { GetUserInfo(this, UD_ID_DOMAIN, (PVOID*)&pszValue); } else { pszValue = CmStrCpyAlloc(this->szDomain); } return pszValue; } // // Profile // if (lstrcmpiU(pszName,TEXT("Profile")) == 0) { return CmStrCpyAlloc(this->piniProfile->GetFile()); } // // ServiceDir // if (lstrcmpiU(pszName, TEXT("ServiceDir")) == 0) { LPTSTR pszServiceDir = NULL; // start with the file name of the Service LPCTSTR pszService = this->piniService->GetFile(); if (pszService) { // find out where the filename.cmp portion starts LPTSTR pszTmp = CmStrrchr(pszService, TEXT('\\')); size_t nSize = pszTmp - pszService + 1; // alloc enough space for the directory name (and terminating NULL) pszServiceDir = (LPTSTR)CmMalloc( nSize * sizeof(TCHAR)); if (pszServiceDir) { lstrcpynU(pszServiceDir, pszService, nSize); // // The Win32 lstrcpyN function enforces a terminating NULL, // so the above works without requiring any further code. // } } return pszServiceDir; } // // ServiceName // if (lstrcmpiU(pszName,c_pszCmEntryServiceName) == 0) { MYDBGASSERT(this->szServiceName[0]); return CmStrCpyAlloc(this->szServiceName); } // // DialRasPhoneBook // if (lstrcmpiU(pszName, TEXT("DialRasPhoneBook")) == 0) { // // We want to return NULL if this was a direct connection // and we want to return the hidden ras phonebook path if // this was a double dial connection (tunnel over a PPP // connection that we dialed). // if (this->IsDirectConnect()) { return NULL; } else { if (this->fUseTunneling) { return CreateRasPrivatePbk(this); } else { return CmStrCpyAlloc(this->pszRasPbk); } } } // // DialRasEntry // if (lstrcmpiU(pszName, TEXT("DialRasEntry")) == 0) { if (this->IsDirectConnect()) { return NULL; } else { return GetRasConnectoidName(this, this->piniService, FALSE); } } // // TunnelRasPhoneBook // if (lstrcmpiU(pszName, TEXT("TunnelRasPhoneBook")) == 0) { // // If we are not tunneling then we want to make sure that we // return NULL for the tunnel entry name and the tunnel // phonebook // if (this->fUseTunneling) { CMTRACE1(TEXT("GetProperty - TunnelRasPhoneBook is %s"), this->pszRasPbk); return CmStrCpyAlloc(this->pszRasPbk); } else { CMTRACE(TEXT("GetProperty - TunnelRasPhoneBook returns NULL")); return NULL; } } // // TunnelRasEntry // if (lstrcmpiU(pszName, TEXT("TunnelRasEntry")) == 0) { // // If we are not tunneling then we want to make sure that we // return NULL for the tunnel entry name and the tunnel // phonebook // if (this->fUseTunneling) { return GetRasConnectoidName(this, this->piniService, TRUE); } else { return NULL; } } // // AutoRedial, TRUE or FALSE /// if (lstrcmpiU(pszName, TEXT("AutoRedial")) == 0) { // // Return TRUE for the first try. // return CmStrCpyAlloc( this->nRedialCnt != this->nMaxRedials ? TEXT("1") : TEXT("0")); } if (lstrcmpiU(pszName, TEXT("LastErrorSource")) == 0) { return CmStrCpyAlloc(this->szLastErrorSrc); } // // PopName, as the city name in phone-book // if (lstrcmpiU(pszName, TEXT("PopName")) == 0) { if (this->IsDirectConnect()) { // // Ensure no POP description on DirectConnect #324951 // return NULL; } else { // // the szDesc is in the format of "CityName (BaudMin - BaudMax bps)" // We could save the CityNme when we load the phone number from phonebook // But we have to change cmpbk code then. // LPTSTR pszDesc = CmStrCpyAlloc(this->aDialInfo[nDialIdx].szDesc); // // The city name is followed by " (" // LPTSTR pszEnd = CmStrStr(pszDesc, TEXT(" (")); if (pszEnd == NULL) { CmFree(pszDesc); return NULL; } *pszEnd = TEXT('\0'); return pszDesc; } } // // The current favorite // if (lstrcmpiU(pszName, TEXT("CurrentFavorite")) == 0) { return CmStrCpyAlloc(this->pszCurrentAccessPoint); } // // The current tunnel server address // if (lstrcmpiU(pszName, TEXT("TunnelServerAddress")) == 0) { if (this->fUseTunneling) { return this->piniBothNonFav->GPPS(c_pszCmSection, c_pszCmEntryTunnelAddress); } else { return NULL; } } // // The canonical number if there is one and if not then the szPhonenumber field itself. // if (lstrcmpiU(pszName, TEXT("PhoneNumberDialed")) == 0) { if (this->IsDirectConnect()) { return NULL; } else { if (this->aDialInfo[nDialIdx].szCanonical[0]) { return CmStrCpyAlloc(this->aDialInfo[nDialIdx].szCanonical); } else { return CmStrCpyAlloc(this->aDialInfo[nDialIdx].szPhoneNumber); } } } // // ErrorCode in decimal // if (lstrcmpiU(pszName, TEXT("ErrorCode")) == 0) { LPTSTR pszValue = (LPTSTR)CmMalloc(64*sizeof(TCHAR)); // large enough to hold the error code MYDBGASSERT(pszValue); if (pszValue) { wsprintfU(pszValue, TEXT("%d"), this->dwExitCode); } return pszValue; } CMTRACE1(TEXT("%%%s%% not a macro, may be environment variable"), pszName); *pbValidPropertyName = FALSE; return NULL; } //+---------------------------------------------------------------------------- // // Function: GetMainDlgTemplate // // Synopsis: Encapsulates determining which template is to be used // for the main dialog. // // Arguments: ArgsStruct *pArgs - Ptr to global Args struct // // Returns: UINT - Dlg template ID. // // History: nickball Created 9/25/98 // tomkel 01/30/2001 Added support for global credentials UI // by using pArgs->fGlobalCredentialsSupported // //+---------------------------------------------------------------------------- UINT GetMainDlgTemplate(ArgsStruct *pArgs) { MYDBGASSERT(pArgs); if (NULL == pArgs) { MYDBGASSERT(pArgs); return 0; } UINT uiNewMainDlgID = 0; DWORD dwNewTemplateMask = 0; UINT i = 0; // // Currently there are 24 dialogs used in this function. If you add more dialogs // make sure to increase the size of the array and the loop. The dialog templates // aren't in any particular order, since we loop through all of them // comparing the masks until we find the correct one. // DWORD rdwTemplateIDs[24][2] = { {CMTM_FAVS | CMTM_U_P_D | CMTM_GCOPT, IDD_MAIN_ALL_USERDATA_FAV_GCOPT}, {CMTM_FAVS | CMTM_U_P_D, IDD_MAIN_ALL_USERDATA_FAV}, {CMTM_FAVS | CMTM_UID, IDD_MAIN_UID_ONLY_FAV}, {CMTM_FAVS | CMTM_PWD | CMTM_GCOPT, IDD_MAIN_PWD_ONLY_FAV_GCOPT}, {CMTM_FAVS | CMTM_PWD, IDD_MAIN_PWD_ONLY_FAV}, {CMTM_FAVS | CMTM_DMN, IDD_MAIN_DMN_ONLY_FAV}, {CMTM_FAVS | CMTM_UID_AND_PWD | CMTM_GCOPT, IDD_MAIN_UID_AND_PWD_FAV_GCOPT}, {CMTM_FAVS | CMTM_UID_AND_PWD, IDD_MAIN_UID_AND_PWD_FAV}, {CMTM_FAVS | CMTM_UID_AND_DMN, IDD_MAIN_UID_AND_DMN_FAV}, {CMTM_FAVS | CMTM_PWD_AND_DMN | CMTM_GCOPT, IDD_MAIN_PWD_AND_DMN_FAV_GCOPT}, {CMTM_FAVS | CMTM_PWD_AND_DMN, IDD_MAIN_PWD_AND_DMN_FAV}, {CMTM_FAVS, IDD_MAIN_NO_USERDATA_FAV}, {CMTM_U_P_D | CMTM_GCOPT, IDD_MAIN_ALL_USERDATA_GCOPT}, {CMTM_U_P_D, IDD_MAIN_ALL_USERDATA}, {CMTM_UID, IDD_MAIN_UID_ONLY}, {CMTM_PWD | CMTM_GCOPT, IDD_MAIN_PWD_ONLY_GCOPT}, {CMTM_PWD, IDD_MAIN_PWD_ONLY}, {CMTM_DMN, IDD_MAIN_DMN_ONLY}, {CMTM_UID_AND_PWD | CMTM_GCOPT, IDD_MAIN_UID_AND_PWD_GCOPT}, {CMTM_UID_AND_PWD, IDD_MAIN_UID_AND_PWD}, {CMTM_UID_AND_DMN, IDD_MAIN_UID_AND_DMN}, {CMTM_PWD_AND_DMN | CMTM_GCOPT, IDD_MAIN_PWD_AND_DMN_GCOPT}, {CMTM_PWD_AND_DMN, IDD_MAIN_PWD_AND_DMN}, {0, IDD_MAIN_NO_USERDATA}}; // // Set the mask according to the pArgs flags for each value. // if (!pArgs->fHideUserName) { dwNewTemplateMask |= CMTM_UID; } // // If the password edit is not displayed, there is no need to // check for the global creds flag since there are no such dialogs // if (!pArgs->fHidePassword) { dwNewTemplateMask |= CMTM_PWD; // // Since we show the password field, lets check if we should display // the global creds option as well. // if (pArgs->fGlobalCredentialsSupported) { dwNewTemplateMask |= CMTM_GCOPT; } } if (!pArgs->fHideDomain) { dwNewTemplateMask |= CMTM_DMN; } if (pArgs->fAccessPointsEnabled) { dwNewTemplateMask |= CMTM_FAVS; } // // Now find the corresponding template id // for (i = 0; i < 24; i++) { if (rdwTemplateIDs[i][0] == dwNewTemplateMask) { uiNewMainDlgID = rdwTemplateIDs[i][1]; break; } } if (0 == uiNewMainDlgID) { MYDBGASSERT(FALSE); uiNewMainDlgID = IDD_MAIN_NO_USERDATA; } return uiNewMainDlgID; } //+---------------------------------------------------------------------------- // // Function: Connect // // Synopsis: The main dialing (connect path) replaces the winmain from the // original CMMGR32.EXE // // Arguments: HWND hwndParent - window handle of parent // LPCTSTR lpszEntry - Ptr to the name of the connection entry // LPTSTR lpszPhonebook - Ptr to the name of the phonebook // LPRASDIALDLG lpRasDialDlg - RasDialDlg data - ignored // LPRASENTRYDLG lpRasEntryDlg - RasEntryDlg data - ignored // LPCMDIALINFO lpCmInfo - CM specific dial info such as flags // DWORD dwFlags - Flags for AllUser, SingleUser, EAP, etc. // PVOID pvLogonBlob - Ptr to blob passed by RAS at WinLogon on W2K // // Returns: Nothing // // Note: RasDialDlg->hwndOwner and RasDialDlg->hwndOwner are honored, but they // are currently passed in via the hwndParent parameter as appropriate by // the caller, CmCustomDialDlg. // // History: nickball Created 02/06/98 // nickball hwndParent 11/10/98 // nickball Passed down dwFlags instead of BOOL 07/13/99 // //+---------------------------------------------------------------------------- HRESULT Connect(HWND hwndParent, LPCTSTR pszEntry, LPTSTR lpszPhonebook, LPRASDIALDLG, // lpRasDialDlg, LPRASENTRYDLG, // lpRasEntryDlg, LPCMDIALINFO lpCmInfo, DWORD dwFlags, PVOID pvLogonBlob) { MYDBGASSERT(pszEntry); MYDBGASSERT(pszEntry[0]); MYDBGASSERT(lpCmInfo); CMTRACE(TEXT("Connect()")); if (NULL == pszEntry || NULL == lpCmInfo) { return E_POINTER; } if (0 == pszEntry[0]) { return E_INVALIDARG; } HRESULT hrRes = S_OK; // // Allocate our args struct from the heap. Not on our stack. // ArgsStruct* pArgs = (ArgsStruct*) CmMalloc(sizeof(ArgsStruct)); if (NULL == pArgs) { hrRes = HRESULT_FROM_WIN32(ERROR_ALLOCATING_MEMORY); goto done; } // // Clear and init global args struct // hrRes = InitArgsForConnect(pArgs, lpszPhonebook, lpCmInfo, (dwFlags & RCD_AllUsers)); if (FAILED(hrRes)) { goto done; } // // Setup the connection table // hrRes = CreateConnTable(pArgs); if (FAILED(hrRes)) { goto done; } // // Initialize the profile // hrRes = InitProfile(pArgs, pszEntry); if (FAILED(hrRes)) { goto done; } // // Make sure we have a .cmp name and that the specified .cms exists // if (FALSE == CheckProfileIntegrity(pArgs)) { // CheckProfileIntegrity() will set pArgs->dwExitCode accordingly goto done; } // // Initialize logging // (VOID) InitLogging(pArgs, pszEntry, TRUE); // TRUE => write a banner; // ignore return value // // Pick up any pre-existing credentials (eg. WinLogon, Reconnect) // hrRes = InitCredentials(pArgs, lpCmInfo, dwFlags, pvLogonBlob); if (S_OK != hrRes) { goto done; } // // Now that credential support and existance flags are initialized we need // to initialize the read/write flags in order to support global user // info. This can only be called only after InitCredentials // SetIniObjectReadWriteFlags(pArgs); // // Calling InitConnect depends on having the Ini objects read/write flags initialized correctly // thus this calls needs to happen after SetIniObjectReadWriteFlags. This is important in case // of ICS where it needs to be able to read data correctly from the ICSData reg key or default to // the .cms/.cmp files. // if (!InitConnect(pArgs)) { goto done; } // // Register Classes // RegisterBitmapClass(g_hInst); RegisterWindowClass(g_hInst); // // Get the helpfile path // LoadHelpFileInfo(pArgs); // // If we are in FL_PROPERTIES mode, just get the settings from the // profile. Otherwise go ahead and launch the MainDlgProc // if (pArgs->dwFlags & FL_PROPERTIES) { if (*pArgs->piniProfile->GetFile() && SetupInternalInfo(pArgs, NULL)) { OnMainProperties(hwndParent, pArgs); } } else { // // Need to call OleInitialize()? See if we need FutureSplash. We don't display // animations at WinLogon because of the security implications. // if (pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryAnimatedLogo) && !IsLogonAsSystem()) { if (!pArgs->olsOle32Link.hInstOle32) { if (LinkToOle32(&pArgs->olsOle32Link, "OLE32")) { if (pArgs->olsOle32Link.pfnOleInitialize(NULL) != S_OK) { // // Note: it's not fatal to fail OleInitialize(). // We will just load the normal bitmap then. // CMTRACE(TEXT("Connect() OleInitialize failed")); } } else { CMTRACE(TEXT("Connect() LinkToOle32 failed")); } } } // // Launch main dialog // INT_PTR iMainDlgReturn = 0; do { iMainDlgReturn = DialogBoxParamU(g_hInst, MAKEINTRESOURCE(GetMainDlgTemplate(pArgs)), hwndParent, (DLGPROC) MainDlgProc, (LPARAM) pArgs); if (0 != pArgs->dwSCardErr) { // // User entered a bad smartcard PIN. We exit immediately to avoid // locking up the smartcard with multiple incorrect retries. // MYDBGASSERT(BAD_SCARD_PIN(pArgs->dwSCardErr)); hrRes = pArgs->dwSCardErr; goto done; } } while (ID_OK_RELAUNCH_MAIN_DLG == iMainDlgReturn); } done: // // Now that we are done, we should clear up all the messes :) // CleanupConnect(pArgs); // // Un-initialize logging // (VOID) pArgs->Log.DeInit(); // ignore return value // // If hRes isn't already set, use the exitcode value // if (S_OK == hrRes) { hrRes = HRESULT_FROM_WIN32(pArgs->dwExitCode); } // // Release pArgs, and exit completely // CmFree(pArgs); return hrRes; } // // Define funtion prototypes for EAP functions // that are implemented in the actual EAP dll. // typedef DWORD (WINAPI* pfnRasEapGetIdentity)( DWORD, HWND, DWORD, const WCHAR*, const WCHAR*, PBYTE, DWORD, PBYTE, DWORD, PBYTE*, DWORD*, WCHAR** ); typedef DWORD (WINAPI* pfnRasEapFreeMemory)( PBYTE ); //+---------------------------------------------------------------------------- // // Function: CmEapGetIdentity // // Synopsis: Given EapUserData, looks up and calls RasEapGetIdentity for // the current EAP. Designed to handle the WinLogon case when we // want to use the EapUserData passed to us, rather then letting // RasGetEapUserIdentity look it up. Because it is only used in // this case we pass RAS_EAP_FLAG_LOGON this enables other EAPs // to disregard the data if necessary. // // Arguments: ArgsStruct *pArgs - Ptr to global args struct // LPTSTR lpszPhonebook - Ptr to the RAS phonebook // LPBYTE pbEapAuthData - Eap auth data blob // DWORD dwEapAuthDataSize - size of the Eap auth data blob // DWORD dwCustomAuthKey - The EAP identifier // LPRASEAPUSERIDENTITY* ppRasEapUserIdentity - Identity data // // Returns: Error Code // // History: nickball Created 07/16/99 // nickball ppRasEapUserIdentity 07/30/99 // //+---------------------------------------------------------------------------- static DWORD CmEapGetIdentity(ArgsStruct *pArgs, LPTSTR pszRasPbk, LPBYTE pbEapAuthData, DWORD dwEapAuthDataSize, DWORD dwCustomAuthKey, LPRASEAPUSERIDENTITY* ppRasEapUserIdentity) { MYDBGASSERT(OS_NT5); MYDBGASSERT(pArgs); MYDBGASSERT(ppRasEapUserIdentity); MYDBGASSERT(pArgs->lpEapLogonInfo); if (NULL == pArgs || NULL == pArgs->lpEapLogonInfo || NULL == ppRasEapUserIdentity) { return ERROR_INVALID_PARAMETER; } DWORD dwErr = ERROR_SUCCESS; DWORD dwTmp = 0; DWORD dwSize = 0; DWORD cbDataOut = 0; LPBYTE pbDataOut = NULL; WCHAR* pwszIdentity = NULL; HKEY hKeyEap = NULL; HINSTANCE hInst = NULL; LPWSTR pszwPath = NULL; pfnRasEapFreeMemory pfnEapFreeMemory = NULL; pfnRasEapGetIdentity pfnEapGetIdentity = NULL; // // First we have to locate the Identity DLL for our EAP. Step one is to // build the reg key name using the base path and EAP number. // WCHAR szwTmp[MAX_PATH]; wsprintfU(szwTmp, TEXT("%s\\%u"), c_pszRasEapRegistryLocation, dwCustomAuthKey); // // Now we can open the EAP key // dwErr = RegOpenKeyExU(HKEY_LOCAL_MACHINE, szwTmp, 0, KEY_QUERY_VALUE , &hKeyEap); CMTRACE2(TEXT("CmEapGetIdentity - Opening %s returns %u"), szwTmp, dwErr); if (ERROR_SUCCESS != dwErr) { return dwErr; } // // See if the EAP supports RasEapGetIdentity // dwSize = sizeof(dwSize); dwErr = RegQueryValueExU(hKeyEap, c_pszInvokeUsernameDialog, NULL, NULL, (BYTE*)&dwTmp, &dwSize); CMTRACE2(TEXT("CmEapGetIdentity - Opening %s returns %u"), c_pszInvokeUsernameDialog, dwErr); if ((dwErr) || (0 != dwTmp)) { dwErr = ERROR_INVALID_FUNCTION_FOR_ENTRY; goto CmEapGetIdentityExit; } // // Next we need to retrieve the path of the EAP's identity DLL // dwSize = sizeof(szwTmp); dwErr = RegQueryValueExU(hKeyEap, c_pszRasEapValueNameIdentity, NULL, NULL, (LPBYTE) szwTmp, &dwSize); CMTRACE2(TEXT("CmEapGetIdentity - Opening %s returns %u"), c_pszRasEapValueNameIdentity, dwErr); if (ERROR_SUCCESS != dwErr) { return dwErr; } pszwPath = (LPWSTR) CmMalloc(MAX_PATH * sizeof(TCHAR)); if (NULL == pszwPath) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto CmEapGetIdentityExit; } ExpandEnvironmentStringsU(szwTmp, pszwPath, MAX_PATH); // // Finally we have the path to the identity DLL. Now we can load the DLL // and get the address of the RasEapGetIdentity and RasEapFreeMemory funcs. // CMTRACE1(TEXT("CmEapGetIdentity - Loading EAP Identity DLL %s"), pszwPath); hInst = LoadLibraryExU(pszwPath, NULL, 0); if (NULL == hInst) { dwErr = GetLastError(); goto CmEapGetIdentityExit; } pfnEapFreeMemory = (pfnRasEapFreeMemory) GetProcAddress(hInst, "RasEapFreeMemory"); pfnEapGetIdentity = (pfnRasEapGetIdentity) GetProcAddress(hInst, "RasEapGetIdentity"); if (pfnEapGetIdentity && pfnEapFreeMemory) { dwErr = pfnEapGetIdentity(dwCustomAuthKey, pArgs->hwndMainDlg, RAS_EAP_FLAG_LOGON | RAS_EAP_FLAG_PREVIEW, pszRasPbk, pArgs->pRasDialParams->szEntryName, pbEapAuthData, dwEapAuthDataSize, (LPBYTE) pArgs->lpEapLogonInfo, pArgs->lpEapLogonInfo->dwSize, &pbDataOut, &cbDataOut, &pwszIdentity); CMTRACE3(TEXT("CmEapGetIdentity - RasEapGetIdentity returns %u, cbDataOut is %u, pwszIdentity is %s"), dwErr, cbDataOut, pwszIdentity); if (ERROR_SUCCESS == dwErr) { // // If data was returned, use it. Otherwise, use the // blob that was given to us by RAS at WinLogon. // if (cbDataOut) { dwSize = cbDataOut; } else { CMTRACE(TEXT("CmEapGetIdentity - there was no pbDataOut from the EAP, using lpEapLogonInfo")); CMTRACE1(TEXT("CmEapGetIdentity - pArgs->lpEapLogonInfo->dwSize is %u"), pArgs->lpEapLogonInfo->dwSize); CMTRACE1(TEXT("CmEapGetIdentity - dwLogonInfoSize is %u"), pArgs->lpEapLogonInfo->dwLogonInfoSize); CMTRACE1(TEXT("CmEapGetIdentity - dwOffsetLogonInfo is %u"), pArgs->lpEapLogonInfo->dwOffsetLogonInfo); CMTRACE1(TEXT("CmEapGetIdentity - dwPINInfoSize is %u"), pArgs->lpEapLogonInfo->dwPINInfoSize); CMTRACE1(TEXT("CmEapGetIdentity - dwOffsetPINInfo is %u"), pArgs->lpEapLogonInfo->dwOffsetPINInfo); dwSize = pArgs->lpEapLogonInfo->dwSize; pbDataOut = (LPBYTE) pArgs->lpEapLogonInfo; // Note: pbDataOut is not our memory } // // Allocate the structure. // *ppRasEapUserIdentity = (LPRASEAPUSERIDENTITY) CmMalloc((sizeof(RASEAPUSERIDENTITY) - 1) + dwSize); if (NULL == *ppRasEapUserIdentity) { dwErr = ERROR_NOT_ENOUGH_MEMORY; goto CmEapGetIdentityExit; } if (pbDataOut) // no crashy { CMTRACE1(TEXT("CmEapGetIdentity - filling *ppRasEapUserIdentity with pbDataOut of size %u"), dwSize); lstrcpyn((*ppRasEapUserIdentity)->szUserName, pwszIdentity, UNLEN); (*ppRasEapUserIdentity)->szUserName[UNLEN] = 0; (*ppRasEapUserIdentity)->dwSizeofEapInfo = dwSize; CopyMemory((*ppRasEapUserIdentity)->pbEapInfo, pbDataOut, dwSize); CMTRACE1(TEXT("CmEapGetIdentity - *ppRasEapUserIdentity filled with pbDataOut of size %u"), dwSize); } else { dwErr = ERROR_INVALID_DATA; MYDBGASSERT(FALSE); goto CmEapGetIdentityExit; } } } else { dwErr = GetLastError(); } CmEapGetIdentityExit: // // Cleanup our temporary buffers // if (NULL != pfnEapFreeMemory) { // // If cbDataOut is 0 then pbDataOut points at // EapLogonInfo, which is not ours to free. // if (cbDataOut && (NULL != pbDataOut)) { pfnEapFreeMemory(pbDataOut); } if (NULL != pwszIdentity) { pfnEapFreeMemory((BYTE*)pwszIdentity); } } if (NULL != hKeyEap) { RegCloseKey(hKeyEap); } if (hInst) { FreeLibrary(hInst); } CmFree(pszwPath); CMTRACE1(TEXT("CmEapGetIdentity - returns %u"), dwErr); return dwErr; } //+---------------------------------------------------------------------------- // // Function: GetEapUserId // // Synopsis: Helper func to deal with the details of calling out to RAS for EAP // credentials. // // Arguments: ArgsStruct *pArgs - Ptr to global args struct // HWND hwndDlg - Window handle of dialog to own any UI // LPTSTR lpszPhonebook - Ptr to the RAS phonebook // LPBYTE pbEapAuthData - Eap auth data blob // DWORD dwEapAuthDataSize - Size of the Eap auth data blob. // DWORD dwCustomAuthKey - The EAP identifier // LPRASEAPUSERIDENTITY* ppRasEapUserIdentity - Ptr to RAS EAP identity // struct to be allocated on our behalf. // // Returns: Error Code // // History: nickball Created 05/22/99 // nickball ppRasEapUserIdentity 07/30/99 // //+---------------------------------------------------------------------------- static DWORD GetEapUserId(ArgsStruct *pArgs, HWND hwndDlg, LPTSTR pszRasPbk, LPBYTE pbEapAuthData, DWORD dwEapAuthDataSize, DWORD dwCustomAuthKey, LPRASEAPUSERIDENTITY* ppRasEapUserIdentity) { MYDBGASSERT(OS_NT5); MYDBGASSERT(pArgs); MYDBGASSERT(ppRasEapUserIdentity); MYDBGASSERT(0 == *ppRasEapUserIdentity); // should always be NULL DWORD dwRet = ERROR_SUCCESS; if (NULL == pArgs || NULL == pArgs->rlsRasLink.pfnGetEapUserIdentity || NULL == ppRasEapUserIdentity) { return ERROR_INVALID_PARAMETER; } *ppRasEapUserIdentity = 0; // // If we have data from WinLogon, then use our own version of // GetEapIdentity. Under the covers, RasGetEapUserIdentity calls // GetEapUserData (which potentially prompts the user) and then // GetEapIdentity. Because we already have the equivalent // (from WinLogon) of the data retrieved by GetEapUserData, // we can call RasGetEapIdentity directly. This enables us // to prevent an unnecessary prompt for the identity info that // the user already gave at WinLogon. // if (pArgs->lpEapLogonInfo) { dwRet = CmEapGetIdentity(pArgs, pszRasPbk, pbEapAuthData, dwEapAuthDataSize, dwCustomAuthKey, ppRasEapUserIdentity); } else { DWORD dwEapIdentityFlags = 0; // // Note: In the case that we are called from WinLogon, // but without EAP data, but the connection is configured for EAP // we send the RAS_EAP_FLAG_LOGON flag down to the EAP so it knows // what to do. // if (IsLogonAsSystem() && (CM_LOGON_TYPE_WINLOGON == pArgs->dwWinLogonType)) { dwEapIdentityFlags |= RAS_EAP_FLAG_LOGON; } // // In case we don't want UI set the - RAS_EAP_FLAG_NON_INTERACTIVE // same as RASEAPF_NonInteractive // if (pArgs->dwFlags & FL_UNATTENDED) { dwEapIdentityFlags |= RAS_EAP_FLAG_NON_INTERACTIVE; } else { // // Always prompt for EAP credentials. Otherwise when the PIN is saved // the user has no way of un-saving it because TLS will cache it and // won't display the prompt if it has everything it needs. // dwEapIdentityFlags = RAS_EAP_FLAG_PREVIEW; } // // Our smartcard PIN retry story: If called from winlogon with an EAP blob, // we never retry because we have no way to sending the corrected PIN back // to winlogon. In other cases, we retry once only. // Retrying oftener greatly increases the chance of locking the smartcard. // DWORD dwMaxTries = 3; // essentially arbitrary number. (If a smartcard: most do lock you out after 3 tries.) DWORD dwCurrentTry = 0; do { dwRet = pArgs->rlsRasLink.pfnGetEapUserIdentity( pszRasPbk, pArgs->pRasDialParams->szEntryName, dwEapIdentityFlags, // See Note above hwndDlg, ppRasEapUserIdentity); } while ((dwCurrentTry++ < dwMaxTries) && (ERROR_SUCCESS != dwRet) && (ERROR_CANCELLED != dwRet)); // // We also clear the password and domain in this case because // they become irrelevant and we don't want to mix CAD credentials // with smartcard credentials. Specifically, we don't want a clash // between the UPN username that EAP usually produces and the // standard username, domain provided with CAD at WinLogon. // lstrcpy(pArgs->pRasDialParams->szPassword, TEXT("")); lstrcpy(pArgs->pRasDialParams->szDomain, TEXT("")); } switch (dwRet) { // // If user id isn't required, succeed // case ERROR_INVALID_FUNCTION_FOR_ENTRY: dwRet = ERROR_SUCCESS; break; // // Retrieve the EAP credential data and store in dial params // case ERROR_SUCCESS: // // Copy Eap info to Dial Params and Dial Extensions for dialing // CMTRACE(TEXT("GetEapUserId() setting dial extension with *ppRasEapUserIdentity->pbEapInfo")); lstrcpy(pArgs->pRasDialParams->szUserName, (*ppRasEapUserIdentity)->szUserName); ((LPRASDIALEXTENSIONS_V500) pArgs->pRasDialExtensions)->RasEapInfo.dwSizeofEapInfo = (*ppRasEapUserIdentity)->dwSizeofEapInfo; ((LPRASDIALEXTENSIONS_V500) pArgs->pRasDialExtensions)->RasEapInfo.pbEapInfo = (*ppRasEapUserIdentity)->pbEapInfo; break; default: break; } if (ERROR_SUCCESS == dwRet) { // // We have a user (identity) now, update internal and external records // so that this information can be reported out. If we're dialing a // tunnel, or its not a tunneling profile, store the name in the // UserName cache, otherwise its the dial-up portion of double-dial // and we store the identity in the InetUserName cache. #388199 // if ((!UseTunneling(pArgs, pArgs->nDialIdx)) || IsDialingTunnel(pArgs)) { lstrcpy(pArgs->szUserName, pArgs->pRasDialParams->szUserName); SaveUserInfo(pArgs, UD_ID_USERNAME, (PVOID)pArgs->pRasDialParams->szUserName); SaveUserInfo(pArgs, UD_ID_DOMAIN, (PVOID)pArgs->pRasDialParams->szDomain); } else { lstrcpy(pArgs->szInetUserName, pArgs->pRasDialParams->szUserName); SaveUserInfo(pArgs, UD_ID_INET_USERNAME, (PVOID)pArgs->szInetUserName); } } CMTRACE2(TEXT("GetEapUserId() returns %u (0x%x)"), dwRet, dwRet); return dwRet; } //+---------------------------------------------------------------------------- // // Func: ShowAccessPointInfoFromReg // // Desc: Get the access points from the registry and populate the combo box // passed as input to the function // // Args: ArgsStruct *pArgs - Ptr to global args struct // HWND hwndCombo - Handle to the combo box to puopulate // // Return: BOOL - Success or failure // // Notes: // // History: t-urama 07/28/2000 Created //----------------------------------------------------------------------------- BOOL ShowAccessPointInfoFromReg(ArgsStruct *pArgs, HWND hwndParent, UINT uiComboID) { MYDBGASSERT(pArgs); if ((NULL == pArgs) || (NULL == hwndParent) || (NULL == pArgs->pszCurrentAccessPoint)) { return FALSE; } LPTSTR pszKeyName = NULL; DWORD dwTypeTmp; DWORD dwSizeTmp = 1; HKEY hKeyCm; DWORD dwRes = 1; DWORD dwIndex = 0; PFILETIME pftLastWriteTime = NULL; LPTSTR pszRegPath = BuildUserInfoSubKey(pArgs->szServiceName, pArgs->fAllUser); MYDBGASSERT(pszRegPath); if (NULL == pszRegPath) { return FALSE; } CmStrCatAlloc(&pszRegPath, TEXT("\\")); CmStrCatAlloc(&pszRegPath, c_pszRegKeyAccessPoints); MYDBGASSERT(pszRegPath); if (NULL == pszRegPath) { return FALSE; } // // Open the sub key under HKCU // dwRes = RegOpenKeyExU(HKEY_CURRENT_USER, pszRegPath, 0, KEY_READ, &hKeyCm); // // If we opened the key successfully, retrieve the value // if (ERROR_SUCCESS == dwRes) { HWND hwndCombo = GetDlgItem(hwndParent, uiComboID); if (hwndCombo) { SendDlgItemMessageU(hwndParent, uiComboID, CB_RESETCONTENT, 0, 0L); do { dwSizeTmp = 1; do { CmFree(pszKeyName); dwSizeTmp = dwSizeTmp + MAX_PATH; MYDBGASSERT(dwSizeTmp < 320); if (dwSizeTmp > 320) { RegCloseKey(hKeyCm); goto ShowError; } pszKeyName = (LPTSTR) CmMalloc((dwSizeTmp + 1) * sizeof(TCHAR)); if (NULL == pszKeyName) { RegCloseKey(hKeyCm); goto ShowError; } dwRes = RegEnumKeyExU(hKeyCm, dwIndex, pszKeyName, &dwSizeTmp, NULL, NULL, NULL, pftLastWriteTime); } while (ERROR_MORE_DATA == dwRes); // now write the name of the sub key to the combo box if (ERROR_SUCCESS == dwRes ) { SendDlgItemMessageU(hwndParent, uiComboID, CB_ADDSTRING, 0, (LPARAM)pszKeyName); } if (ERROR_SUCCESS != dwRes && ERROR_NO_MORE_ITEMS != dwRes) { CMTRACE1(TEXT("ShowAccessPointInfoFromReg() failed, GLE=%u."), GetLastError()); RegCloseKey(hKeyCm); goto ShowError; } dwIndex ++; } while(ERROR_NO_MORE_ITEMS != dwRes); DWORD dwIdx = (DWORD)SendDlgItemMessageU(hwndParent, uiComboID, CB_FINDSTRINGEXACT, 0, (LPARAM)pArgs->pszCurrentAccessPoint); if (dwIdx != CB_ERR) { SendDlgItemMessageU(hwndParent, uiComboID, CB_SETCURSEL, (WPARAM)dwIdx, 0L); } else { LPTSTR pszDefaultAccessPointName = CmLoadString(g_hInst, IDS_DEFAULT_ACCESSPOINT); CMASSERTMSG(pszDefaultAccessPointName, TEXT("ShowAccessPointInfoFromReg -- CmLoadString of IDS_DEFAULT_ACCESSPOINT failed")); if (pszDefaultAccessPointName) { dwIdx = (DWORD)SendDlgItemMessageU(hwndParent, uiComboID, CB_FINDSTRINGEXACT, 0, (LPARAM)pszDefaultAccessPointName); if (dwIdx != CB_ERR) { SendDlgItemMessageU(hwndParent, uiComboID, CB_SETCURSEL, (WPARAM)dwIdx, 0L); ChangedAccessPoint(pArgs, hwndParent, uiComboID); } CmFree(pszDefaultAccessPointName); } } } CmFree(pszKeyName); CmFree(pszRegPath); RegCloseKey(hKeyCm); return TRUE; } ShowError: CmFree(pszRegPath); CmFree(pszKeyName); return FALSE; } //+---------------------------------------------------------------------------- // // Func: ChangedAccessPoint // // Desc: Changes the values of access point relevant stuff in pArgs // if the value of the current access point changes // // Args: ArgsStruct *pArgs - Ptr to global args struct // // Return: BOOL - True if the access point has changed // // Notes: // // History: t-urama 07/28/2000 Created //----------------------------------------------------------------------------- BOOL ChangedAccessPoint(ArgsStruct *pArgs, HWND hwndDlg, UINT uiComboID) { BOOL bReturn = FALSE; MYDBGASSERT(pArgs); MYDBGASSERT(hwndDlg); if ((NULL == pArgs) || (NULL == hwndDlg) || (NULL == pArgs->pszCurrentAccessPoint)) { return FALSE; } HWND hwndCombo = GetDlgItem(hwndDlg, uiComboID); if (hwndCombo) { LPTSTR pszAccessPoint = NULL; LRESULT lRes = 0; LRESULT lResTextLen = 0; // // Need to get the currently selected text from the combobox. // Previously we used GetWindowTextU(hwndCombo, szAccessPoint, MAX_PATH+1), but it // incorrectly returned the text. // First get the selected index, find out the string length, allocate memory // lRes = SendMessageU(hwndCombo, CB_GETCURSEL, (WPARAM)0, (LPARAM)0); if (CB_ERR != lRes) { lResTextLen = SendMessageU(hwndCombo, CB_GETLBTEXTLEN, (WPARAM)lRes, (LPARAM)0); if (CB_ERR != lResTextLen) { pszAccessPoint = (LPTSTR)CmMalloc(sizeof(TCHAR)*(lResTextLen+1)); if (NULL != pszAccessPoint) { // // Retrieve the text. // lRes = SendMessageU(hwndCombo, CB_GETLBTEXT, (WPARAM)lRes, (LPARAM)pszAccessPoint); if (CB_ERR != lRes) { if (0 != lstrcmpiU(pArgs->pszCurrentAccessPoint, pszAccessPoint)) { CmFree(pArgs->pszCurrentAccessPoint); pArgs->pszCurrentAccessPoint = CmStrCpyAlloc(pszAccessPoint); if (pArgs->pszCurrentAccessPoint) { LPTSTR pszRegPath = FormRegPathFromAccessPoint(pArgs); if (pszRegPath) { pArgs->piniBoth->SetPrimaryRegPath(pszRegPath); pArgs->piniProfile->SetRegPath(pszRegPath); CmFree(pszRegPath); // // First we determine our connect type // GetConnectType(pArgs); // // Set fUseTunneling. If not obvious (eg. direct VPN) then // base the initial value upon the primary phone number. // if (pArgs->IsDirectConnect()) { pArgs->fUseTunneling = TRUE; } else { pArgs->fUseTunneling = UseTunneling(pArgs, 0); } // // Make sure we re-munge the phone number we are about to load. // pArgs->bDialInfoLoaded = FALSE; // // get new values for redial count, idle timeout, and the tapi location // LoadProperties(pArgs); // // get new values for phone info // LoadPhoneInfoFromProfile(pArgs); PickModem(pArgs, pArgs->szDeviceType, pArgs->szDeviceName); CMTRACE1(TEXT("ChangedAccessPoint() - Changed Access point to %s"), pArgs->pszCurrentAccessPoint); bReturn = TRUE; } else { CMASSERTMSG(FALSE, TEXT("ChangedAccessPoint -- FormRegPathFromAccessPoint returned NULL")); } } else { CMASSERTMSG(FALSE, TEXT("ChangedAccessPoint -- CmStrCpyAlloc returned NULL trying to copy the current access point.")); } } // else, nothing to do if the favorites are the same } else { CMASSERTMSG(FALSE, TEXT("ChangedAccessPoint -- SendMessageU(hwndCombo, CB_GETLBTEXT,...) returned CB_ERR")); } } else { CMASSERTMSG(FALSE, TEXT("ChangedAccessPoint -- Unable to allocate memory")); } CmFree(pszAccessPoint); } else { CMASSERTMSG(FALSE, TEXT("ChangedAccessPoint -- SendMessageU(hwndCombo, CB_GETLBTEXTLEN,...) returned CB_ERR")); } } else { CMASSERTMSG(FALSE, TEXT("ChangedAccessPoint -- SendMessageU(hwndCombo, CB_GETCURSEL,...) returned CB_ERR")); } } else { CMASSERTMSG(FALSE, TEXT("ChangedAccessPoint -- Unable to get the combo HWND")); } return bReturn; } //---------------------------------------------------------------------------- // // Function: FindEntryCredentialsForCM // // Synopsis: The algorithm and most of the code is taken from RAS and modified // for use by CM. // // This routine determines whether per-user or per-connection credentials exist or // both. // // The logic is a little complicated because RasGetCredentials had to // support legacy usage of the API. // // Here's how it works. If only one set of credentials is stored for a // connection, then RasGetCredentials will return that set regardless of // whether the RASCM_DefaultCreds flag is set. If two sets of credentials // are saved, then RasGetCredentials will return the per-user credentials // if the RASCM_DefaultCreds bit is set, and the per-connection credentials // otherwise. // // Here is the algorithm for loading the credentials // // 1. Call RasGetCredentials with the RASCM_DefaultCreds bit cleared // 1a. If nothing is returned, no credentials are saved // 1b. If the RASCM_DefaultCreds bit is set on return, then only // global credentials are saved. // // 2. Call RasGetCredentials with the RASCM_DefaultCreds bit set // 2a. If the RASCM_DefaultCreds bit is set on return, then // both global and per-connection credentials are saved. // 2b. Otherwise, only per-user credentials are saved. // // Arguments: pArgs - pointer to the ArgStruct // pszPhoneBook - path to the phone book. Could be NULL. // *pfUser - out param set true if per user creds found // *pfGlobal - out param set true if global creds found // // Returns: BOOL - TRUE is succeeds else FALSE // // History: 01/31/2001 tomkel Created // //---------------------------------------------------------------------------- DWORD FindEntryCredentialsForCM(ArgsStruct *pArgs, LPTSTR pszPhoneBook, BOOL *pfUser, BOOL *pfGlobal) { RASCREDENTIALS rc1 = {0}; RASCREDENTIALS rc2 = {0}; BOOL fUseLogonDomain = FALSE; DWORD dwErr = ERROR_INVALID_PARAMETER; LPTSTR pszConnectoid = NULL; CMTRACE(TEXT("FindEntryCredentialsForCM() - Begin")); if (NULL == pArgs || NULL == pfUser || NULL == pfGlobal) { MYDBGASSERT(pArgs && pfUser && pfGlobal); CMTRACE(TEXT("FindEntryCredentialsForCM() - Error! Invalid Parameter.")); return dwErr; } // // Initialize the out params // *pfUser = FALSE; *pfGlobal = FALSE; // // After setting the OUT params, check if RAS dll have been loaded and if we can use the ras creds store // if (NULL == pArgs->rlsRasLink.pfnGetCredentials || FALSE == pArgs->bUseRasCredStore) { CMTRACE(TEXT("FindEntryCredentialsForCM() - RAS Creds store not supported on this platform.")); return ERROR_NOT_SUPPORTED; } // // Set the size of the structures // rc1.dwSize = sizeof(rc1); rc2.dwSize = sizeof(rc2); // // The third parameter is used only on Win9x (for tunneling) thus we set it to FALSE // since this function is called on Win2K+ // pszConnectoid = GetRasConnectoidName(pArgs, pArgs->piniService, FALSE); if (pszConnectoid) { do { // // Look up per-user cached username, password, and domain. // See comment '1.' in the function header // rc1.dwMask = RASCM_UserName | RASCM_Password | RASCM_Domain; dwErr = pArgs->rlsRasLink.pfnGetCredentials(pszPhoneBook, pszConnectoid, &rc1); CMTRACE2(TEXT("FindEntryCredentialsForCM() - Per-User RasGetCredentials=%d,m=%d"), dwErr, rc1.dwMask); if (dwErr != NO_ERROR) { break; } if (0 == rc1.dwMask) { // // See 1a. in the function header comments // dwErr = ERROR_SUCCESS; break; } else if (rc1.dwMask & RASCM_DefaultCreds) { // // See 1b. in the function header comments // *pfGlobal = TRUE; // // Assumed password was not encoded by RasGetCredentials() // CmEncodePassword(rc1.szPassword); dwErr = ERROR_SUCCESS; break; } // // Look up global per-user cached username, password, domain. // See comment 2. in the function header // rc2.dwMask = RASCM_UserName | RASCM_Password | RASCM_Domain | RASCM_DefaultCreds; dwErr = pArgs->rlsRasLink.pfnGetCredentials(pszPhoneBook, pszConnectoid, &rc2); CMTRACE2(TEXT("FindEntryCredentialsForCM() - Global RasGetCredentials=%d,m=%d"), dwErr, rc2.dwMask); if (dwErr != ERROR_SUCCESS) { break; } if (rc2.dwMask & RASCM_DefaultCreds) { // // See 2a. in the function header comments // *pfGlobal = TRUE; if (rc1.dwMask & RASCM_Password) { *pfUser = TRUE; } // // Assumed password was not encoded by RasGetCredentials() // CmEncodePassword(rc1.szPassword); CmEncodePassword(rc2.szPassword); } else { // // See 2b. in the function header comments // if (rc1.dwMask & RASCM_Password) { *pfUser = TRUE; } // // Assumed password was not encoded by RasGetCredentials() // CmEncodePassword(rc1.szPassword); } }while (FALSE); } // // Cleanup // ZeroMemory(rc1.szPassword, sizeof(rc1.szPassword)); ZeroMemory(rc2.szPassword, sizeof(rc2.szPassword)); CmFree(pszConnectoid); CMTRACE(TEXT("FindEntryCredentialsForCM() - End")); return dwErr; } //---------------------------------------------------------------------------- // // Function: InitializeCredentialSupport // // Synopsis: Helper function to initialize user and global credential // support. Some of the flags are redundantly initialized // (to FALSE). That is done on purpose for clarity. // // Arguments: pArgs - the ArgStruct * // // Returns: BOOL - TRUE is succeeds else FALSE // // History: 01/31/2001 tomkel Created // //---------------------------------------------------------------------------- BOOL InitializeCredentialSupport(ArgsStruct *pArgs) { BOOL fGlobalCreds = FALSE; BOOL fGlobalUserSettings = FALSE; if (NULL == pArgs) { MYDBGASSERT(pArgs); return FALSE; } // // By default the the Internet Connection Sharing & Internet Connection // Firewall (ICS) tab is disabled. // pArgs->bShowHNetCfgAdvancedTab = FALSE; // // User profile read/write support when user is logged off or using dial-up // This flag determines if the user info needs to be also saved or loaded from // the .cmp file // pArgs->dwGlobalUserInfo = 0; // // Credential existance flags - here we cannot yet determine which creds exist // that is done in a later call to RefreshCredentialTypes // pArgs->dwExistingCredentials = 0; // // Default for which credential store to use - set based on the existance flag so // this will also get set appropriatelly after a call to RefreshCredentialTypes // pArgs->dwCurrentCredentialType = CM_CREDS_USER; // // Deletion flags - used to mark a set of creds for deletion. Since the // user can Cancel out of a dialog we don't want to commit the changed // until we actually do a dial. // pArgs->dwDeleteCredentials = 0; // // Check if this is WindowsXP. We want display the Advanced tab for single-user and // all-user profiles // if (OS_NT51) { if (IsLogonAsSystem()) { // // LocalSystem - winlogon or ICS (in both cases user is logged off) // WinLogon - creds are passed through MSGina // ICS - need to use glocal creds store // pArgs->dwWinLogonType was intialized in InitCredentials() // We don't want to read ICSData info if this is a single user profile // if (CM_LOGON_TYPE_WINLOGON == pArgs->dwWinLogonType || FALSE == pArgs->fAllUser) { pArgs->fGlobalCredentialsSupported = FALSE; pArgs->dwCurrentCredentialType = CM_CREDS_USER; pArgs->dwGlobalUserInfo = 0; } else { pArgs->fGlobalCredentialsSupported = TRUE; pArgs->dwCurrentCredentialType = CM_CREDS_GLOBAL; pArgs->dwGlobalUserInfo |= CM_GLOBAL_USER_INFO_READ_ICS_DATA ; } CMTRACE(TEXT("InitializeCredentialSupport() - LocalSystem - Global creds OK.")); } else { // // User is logged on // // // By default we want to we want to display the tab. By negating // this value we can then correctly save it in the Args structure. This // needs to be initialized for everyone // const TCHAR* const c_pszCmEntryHideICFICSAdvancedTab = TEXT("HideAdvancedTab"); pArgs->bShowHNetCfgAdvancedTab = !(pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideICFICSAdvancedTab, FALSE)); // // If this an all-user profile then we want to see if the profile enables // global user settings and displays global credential options. // These two features are disabled for single user profiles with the exception of // showing the Advanced (ICS) tab // if (pArgs->fAllUser) { // // If ICS is enabled then we need to support global user settings. // Otherwise we read the setting from the file // if (pArgs->bShowHNetCfgAdvancedTab) { fGlobalUserSettings = TRUE; } else { // // See if we support global user settings. By default is it off except if ICS is enabled // const TCHAR* const c_pszCmEntryGlobalUserSettings = TEXT("GlobalUserSettings"); fGlobalUserSettings = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryGlobalUserSettings, FALSE); } // // Read the info from the .cms file. By default global credentials are supported // const TCHAR* const c_pszCmEntryHideGlobalCredentials = TEXT("GlobalCredentials"); fGlobalCreds = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideGlobalCredentials, TRUE); } // // Check to see if we are going to be hiding the Save Password option, if so then // we don't want to support global credentials // pArgs->fHideRememberPassword = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryHideRememberPwd); if (fGlobalCreds && FALSE == pArgs->fHideRememberPassword) { // // Global creds are supported // // // Pick a default for creds type - it might change after calling RefreshCredentialTypes // pArgs->fGlobalCredentialsSupported = TRUE; pArgs->dwCurrentCredentialType = CM_CREDS_USER; if (fGlobalUserSettings) { pArgs->dwGlobalUserInfo |= CM_GLOBAL_USER_INFO_WRITE_ICS_DATA; } CMTRACE(TEXT("InitializeCredentialSupport() - User, global creds, show global UI.")); } else { // // Global creds not supported // pArgs->fGlobalCredentialsSupported = FALSE; pArgs->dwCurrentCredentialType = CM_CREDS_USER; pArgs->dwGlobalUserInfo = 0; CMTRACE(TEXT("InitializeCredentialSupport() - User, no global creds, normal UI.")); } } } else { // // Single user or not WindowsXP // pArgs->fGlobalCredentialsSupported = FALSE; pArgs->dwCurrentCredentialType = CM_CREDS_USER; pArgs->dwGlobalUserInfo = 0; CMTRACE(TEXT("InitializeCredentialSupport() - Single User profile or not WindowsXP. Global creds not supported")); } return TRUE; } //---------------------------------------------------------------------------- // // Function: RefreshCredentialTypes // // Synopsis: This refreshes credential info. If fSetCredsDefault is TRUE // then we also need to set the default type: // pArgs->dwCurrentCredentialType. // // // Arguments: pArgs - the ArgStruct * // fSetCredsDefault- used to set the default creds type // // Returns: BOOL - TRUE is succeeds else FALSE // // History: 01/31/2001 tomkel Created // //---------------------------------------------------------------------------- BOOL RefreshCredentialTypes(ArgsStruct *pArgs, BOOL fSetCredsDefault) { DWORD dwRC = ERROR_INVALID_PARAMETER; LPTSTR pszPrivatePbk = NULL; if (NULL == pArgs) { MYDBGASSERT(pArgs); return FALSE; } // // This should be run on Win2K+ whether this is an all user profile or not // The call that actually determines which credentials exist makes sure we // can use the ras cred store // if (OS_NT5) { BOOL fUserCredsExist = FALSE; BOOL fGlobalCredsExist = FALSE; // // See if the main creds exist. Inside the function we determine whether // we can use the RAS cred store // dwRC = FindEntryCredentialsForCM(pArgs, pArgs->pszRasPbk, &fUserCredsExist, &fGlobalCredsExist); if (ERROR_SUCCESS == dwRC) { CMTRACE2(TEXT("RefreshCredentialTypes() - FindEntryCredentialsForCM returned: (Main) User=%d, Global=%d"), fUserCredsExist, fGlobalCredsExist); } else { CMTRACE(TEXT("RefreshCredentialTypes() - FindEntryCredentialsForCM returned an error. (Main)")); } // // Set the existence flags // if (fUserCredsExist) { pArgs->dwExistingCredentials |= CM_EXIST_CREDS_MAIN_USER; } else { pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_USER; } if (fGlobalCredsExist) { pArgs->dwExistingCredentials |= CM_EXIST_CREDS_MAIN_GLOBAL; } else { pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_GLOBAL; } fUserCredsExist = FALSE; fGlobalCredsExist = FALSE; pszPrivatePbk = CreateRasPrivatePbk(pArgs); if (pszPrivatePbk) { // // See if the Internet creds exist - by using the private phonebook // Inside the function we determine whether we can use the RAS cred store // dwRC = FindEntryCredentialsForCM(pArgs, pszPrivatePbk, &fUserCredsExist, &fGlobalCredsExist); if (ERROR_SUCCESS == dwRC) { CMTRACE2(TEXT("RefreshCredentialTypes() - FindEntryCredentialsForCM returned: (Internet) User=%d, Global=%d"), fUserCredsExist, fGlobalCredsExist); } else { CMTRACE(TEXT("RefreshCredentialTypes() - FindEntryCredentialsForCM returned an error. (Internet)")); } } // // Set the flags whether or not we successfully created a private pbk // if (fUserCredsExist) { pArgs->dwExistingCredentials |= CM_EXIST_CREDS_INET_USER; } else { pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_USER; } if (fGlobalCredsExist) { pArgs->dwExistingCredentials |= CM_EXIST_CREDS_INET_GLOBAL; } else { pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_GLOBAL; } // // If we don't support Global Creds then explicitly set // the existance to FALSE. This can occur if the .cms flag // is set not to support global creds, but there are actually // global creds on the system. // if (FALSE == pArgs->fGlobalCredentialsSupported) { pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_GLOBAL; pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_GLOBAL; CMTRACE(TEXT("RefreshCredentialTypes() - Global Credentials are disabled.")); } if (fSetCredsDefault) { pArgs->dwCurrentCredentialType = GetCurrentCredentialType(pArgs); CMTRACE1(TEXT("RefreshCredentialTypes() - Set default Credentials = %d"), pArgs->dwCurrentCredentialType); } } CmFree(pszPrivatePbk); return TRUE; } //---------------------------------------------------------------------------- // // Function: GetCurrentCredentialType // // Synopsis: Gets the default credentials based on which ones exist based // on which flags are set. This function should be called only // after RefreshCredentialTypes since that function actually // queries the RAS creds store. This one only looks up the cached // status of those creds and determines the default according to // what credentials exist. // // Arguments: pArgs - the ArgStruct * // fSetCredsDefault- used to set the default creds type // // Returns: BOOL - TRUE is succeeds else FALSE // // History: 01/31/2001 tomkel Created // //---------------------------------------------------------------------------- DWORD GetCurrentCredentialType(ArgsStruct *pArgs) { DWORD dwReturn = CM_CREDS_USER; if (NULL == pArgs) { MYDBGASSERT(pArgs); return dwReturn; } // // If Global creds aren't supported as in WinLogon case or single-user // profiles or anything below WinXP, the default is User Creds Store // if (FALSE == pArgs->fGlobalCredentialsSupported) { return dwReturn; } // // Normal Rules when a user is logged on // if (CM_LOGON_TYPE_USER == pArgs->dwWinLogonType) { if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_MAIN_USER) { // // Doesn't matter if main global creds exist since main user credentials // have precendence if both exist // dwReturn = CM_CREDS_USER; } else if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_MAIN_GLOBAL) { dwReturn = CM_CREDS_GLOBAL; } else { // // If none of them exist then we want to default to user creds // dwReturn = CM_CREDS_USER; } } else { // // In any other case dafult to global creds - (ICS scenario) // dwReturn = CM_CREDS_GLOBAL; } return dwReturn; } //---------------------------------------------------------------------------- // // Function: DeleteSavedCredentials // // Synopsis: Helper function to delete credentials from the RAS store. // // Arguments: pArgs - the ArgStruct * // dwCredsType - Normal or Internet credentials // fDeleteGlobal - specifies whether to delete global credentials. // If TRUE we delete user, domain name, // password as well // fDeleteIdentity - specifies whether to delete the user and // domain names in addition to the password // // Returns: BOOL - TRUE is succeeds else FALSE // // History: 01/31/2001 tomkel Created // //---------------------------------------------------------------------------- BOOL DeleteSavedCredentials(ArgsStruct *pArgs, DWORD dwCredsType, BOOL fDeleteGlobal, BOOL fDeleteIdentity) { RASCREDENTIALS rc; BOOL fReturn = FALSE; DWORD dwErr = ERROR_INVALID_PARAMETER; LPTSTR pszConnectoid = NULL; CMTRACE2(TEXT("DeleteSavedCredentials() - Begin: %d %d"), fDeleteGlobal, fDeleteIdentity ); if (NULL == pArgs) { MYDBGASSERT(pArgs); return fReturn; } // // Check if globals should be deleted in case globals are not supported. // This can be in case of global creds are disabled on WinXP or this is // Win2K or the platform < Win2K where RASSetCredentials isn't even supported. // Thus we still should return TRUE // if ((fDeleteGlobal && FALSE == pArgs->fGlobalCredentialsSupported) || (NULL == pArgs->rlsRasLink.pfnSetCredentials) || (FALSE == pArgs->bUseRasCredStore)) { CMTRACE(TEXT("DeleteSavedCredentials() - Global Creds not supported or do not have ras store on this platform.")); return TRUE; } // // We don't support deleting globals on Win2K (that is caught by the above if since Win2K // will not have global credentials supported. Otherwise on Win2K we can delete the main // user creds. On WinXP anything is fine. // if (OS_NT5) { ZeroMemory(&rc, sizeof(rc)); rc.dwSize = sizeof(RASCREDENTIALS); rc.dwMask = RASCM_Password; if (fDeleteIdentity) { rc.dwMask |= (RASCM_UserName | RASCM_Domain); } if (fDeleteGlobal && pArgs->fGlobalCredentialsSupported) { rc.dwMask |= RASCM_UserName | RASCM_Domain | RASCM_DefaultCreds; } // // The third parameter is used only on Win9x (for tunneling) thus we set it to FALSE // since this function is called on Win2K+ // pszConnectoid = GetRasConnectoidName(pArgs, pArgs->piniService, FALSE); if (pszConnectoid) { if (CM_CREDS_TYPE_INET == dwCredsType) { LPTSTR pszPrivatePbk = CreateRasPrivatePbk(pArgs); if (pszPrivatePbk) { dwErr = pArgs->rlsRasLink.pfnSetCredentials(pszPrivatePbk, pszConnectoid, &rc, TRUE ); CmFree(pszPrivatePbk); } } else { dwErr = pArgs->rlsRasLink.pfnSetCredentials(pArgs->pszRasPbk, pszConnectoid, &rc, TRUE ); } if (ERROR_SUCCESS == dwErr) { fReturn = TRUE; } } CMTRACE1(TEXT("DeleteSavedCredentials() - End: RasSetCredentials=%d"), dwErr ); } else { CMTRACE(TEXT("DeleteSavedCredentials() - Platform is less than Win2K")); } CmFree(pszConnectoid); return fReturn; } //+--------------------------------------------------------------------------- // // Function: SetCredentialUIOptionBasedOnDefaultCreds // // Synopsis: Selects (checks) the appropriate UI option for saving credentials // based on the current credential store default. // // Arguments: pArgs - ptr to ArgsStruct // hwndDlg - handle to the dialog window // // Returns: NONE // // History: 02/05/2001 tomkel Created // //---------------------------------------------------------------------------- VOID SetCredentialUIOptionBasedOnDefaultCreds(ArgsStruct *pArgs, HWND hwndDlg) { if (NULL == pArgs || NULL == hwndDlg) { MYDBGASSERT(pArgs && hwndDlg); return; } // // fGlobalCredentialsSupported controls which dialog templates get loaded and // if the flag is FALSE then the dialog template doesn't have these controls // thus there is no reason to set them. // if (pArgs->fGlobalCredentialsSupported) { if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { CheckDlgButton(hwndDlg, IDC_OPT_CREDS_SINGLE_USER, BST_UNCHECKED); CheckDlgButton(hwndDlg, IDC_OPT_CREDS_ALL_USER, BST_CHECKED); } else { // // CM_CREDS_USER // CheckDlgButton(hwndDlg, IDC_OPT_CREDS_SINGLE_USER, BST_CHECKED); CheckDlgButton(hwndDlg, IDC_OPT_CREDS_ALL_USER, BST_UNCHECKED); } } return; } //+--------------------------------------------------------------------------- // // Function: RefreshCredentialInfo // // Synopsis: This is a slimmed down version of LoadProperties. It only // loads user info from cmp/cms, registry, password // cache, etc, into its internal variables. // // // Arguments: pArgs - ptr to ArgsStruct // dwCredsType - type of credentials to refresh // // Returns: NONE // // History: 02/05/2001 tomkel Created // //---------------------------------------------------------------------------- VOID RefreshCredentialInfo(ArgsStruct *pArgs, DWORD dwCredsType) { LPTSTR pszTmp = NULL; LPTSTR pszUserName = NULL; UINT nTmp; CMTRACE(TEXT("RefreshCredentialInfo() - Begin")); if (NULL == pArgs) { MYDBGASSERT(pArgs); return; } if (IsTunnelEnabled(pArgs)) { if (CM_CREDS_TYPE_BOTH == dwCredsType || CM_CREDS_TYPE_INET == dwCredsType) { // // read in inet username // Special case where the same user name isn't being used, and internet globals don't exist // Then we have to read the user name from the user creds store in order to pre-populate // DWORD dwRememberedCredType = pArgs->dwCurrentCredentialType; pszUserName = NULL; if ((FALSE == pArgs->fUseSameUserName) && (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) && (FALSE == (BOOL)(CM_EXIST_CREDS_INET_GLOBAL & pArgs->dwExistingCredentials))) { pArgs->dwCurrentCredentialType = CM_CREDS_USER; } GetUserInfo(pArgs, UD_ID_INET_USERNAME, (PVOID*)&pszUserName); // // Restore credential store // pArgs->dwCurrentCredentialType = dwRememberedCredType; if (pszUserName) { // // check username length // nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxUserName, UNLEN); if ((UINT)lstrlenU(pszUserName) > __min(UNLEN, nTmp)) { CmFree(pszUserName); pArgs->szInetUserName[0] = TEXT('\0'); SaveUserInfo(pArgs, UD_ID_INET_USERNAME, (PVOID)pArgs->szInetUserName); } else { lstrcpyU(pArgs->szInetUserName, pszUserName); CmFree(pszUserName); } } else { *pArgs->szInetUserName = TEXT('\0'); } // // Read in inet password unless we are reconnecting in which case, we // already have the correct password, and we want to use it and dial // automatically. // if (!(pArgs->dwFlags & FL_RECONNECT)) { LPTSTR pszPassword = NULL; GetUserInfo(pArgs, UD_ID_INET_PASSWORD, (PVOID*)&pszPassword); if (!pszPassword) { CmWipePassword(pArgs->szInetPassword); } else { nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxPassword, PWLEN); if ((UINT)lstrlenU(pszPassword) > __min(PWLEN, nTmp)) { CmFree(pszPassword); pszPassword = CmStrCpyAlloc(TEXT("")); } lstrcpyU(pArgs->szInetPassword, pszPassword); CmEncodePassword(pArgs->szInetPassword); // Never leave a PWD in plain text on heap CmWipePassword(pszPassword); CmFree(pszPassword); } } } } if (CM_CREDS_TYPE_BOTH == dwCredsType || CM_CREDS_TYPE_MAIN == dwCredsType) { // // The presence of either lpRasNoUser or lpEapLogonInfo indicates // that we retrieved credentials via WinLogon. We ignore cached // creds in this situation. // if ((!pArgs->lpRasNoUser) && (!pArgs->lpEapLogonInfo)) { // // get username, domain, etc. from CMS file // GetUserInfo(pArgs, UD_ID_USERNAME, (PVOID*)&pszUserName); if (pszUserName) { // // check username length // nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxUserName, UNLEN); if ((UINT)lstrlenU(pszUserName) > __min(UNLEN, nTmp)) { CmFree(pszUserName); pszUserName = CmStrCpyAlloc(TEXT("")); SaveUserInfo(pArgs, UD_ID_USERNAME, (PVOID)pszUserName); } lstrcpyU(pArgs->szUserName, pszUserName); CmFree(pszUserName); } else { *pArgs->szUserName = TEXT('\0'); } // // Read in the standard password unless we are reconnecting in which case // we already have the correct password, and we want to use it and dial // automatically. // if (!(pArgs->dwFlags & FL_RECONNECT)) { pszTmp = NULL; GetUserInfo(pArgs, UD_ID_PASSWORD, (PVOID*)&pszTmp); if (pszTmp) { // // max length for user password // nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection,c_pszCmEntryMaxPassword,PWLEN); if ((UINT)lstrlenU(pszTmp) > __min(PWLEN,nTmp)) { CmFree(pszTmp); pszTmp = CmStrCpyAlloc(TEXT("")); } lstrcpyU(pArgs->szPassword, pszTmp); CmEncodePassword(pArgs->szPassword); // Never leave a PWD in plain text on heap CmWipePassword(pszTmp); CmFree(pszTmp); } else { CmWipePassword(pArgs->szPassword); } } // // Load domain info // LPTSTR pszDomain = NULL; GetUserInfo(pArgs, UD_ID_DOMAIN, (PVOID*)&pszDomain); if (pszDomain) { nTmp = (int) pArgs->piniService->GPPI(c_pszCmSection, c_pszCmEntryMaxDomain, DNLEN); if (nTmp <= 0) { nTmp = DNLEN; } if ((UINT)lstrlenU(pszDomain) > __min(DNLEN, nTmp)) { CmFree(pszDomain); pszDomain = CmStrCpyAlloc(TEXT("")); } lstrcpyU(pArgs->szDomain, pszDomain); CmFree(pszDomain); } else { *pArgs->szDomain = TEXT('\0'); } } } CMTRACE(TEXT("RefreshCredentialInfo() - End")); return; } //+--------------------------------------------------------------------------- // // Function: GetAndStoreUserInfo // // Synopsis: Most of this code existed in the OnMainConnect function. // Gets the username, domain, password from the edit boxes and saves them // to the internal structure pArgs->szUserName, pArgs->szPassword, pArgs->szDomain // if the fSaveOtherUserInfo is TRUE then it also saves them to the appropriate // place (RAS store, reg, etc.) // // Arguments: pArgs - ptr to ArgsStruct // hwndDlg - handle to the dialog window // fSaveUPD - save UserName, Password, Domain (U, P, D) // fSaveOtherUserInfo - flag whether to save other userinfo (excluding U, P, D) // // Returns: NONE // // History: 02/05/2001 tomkel Created // //---------------------------------------------------------------------------- VOID GetAndStoreUserInfo(ArgsStruct *pArgs, HWND hwndDlg, BOOL fSaveUPD, BOOL fSaveOtherUserInfo) { if (NULL == pArgs || NULL == hwndDlg) { MYDBGASSERT(pArgs && hwndDlg); return; } // // Process UserName info, if any // if (GetDlgItem(hwndDlg, IDC_MAIN_USERNAME_EDIT)) { LPTSTR pszUsername = CmGetWindowTextAlloc(hwndDlg, IDC_MAIN_USERNAME_EDIT); // // save the user info // if (fSaveUPD) { SaveUserInfo(pArgs, UD_ID_USERNAME, (PVOID)pszUsername); } lstrcpyU(pArgs->szUserName, pszUsername); CmFree(pszUsername); } else { // // In case the user name field is hidden then just re-save what's in the // structure. This needs to be done since all of the credentials might have // been deleted from the ras cred store // if (fSaveUPD) { SaveUserInfo(pArgs, UD_ID_USERNAME, (PVOID)pArgs->szUserName); } } // // Update password related flags // if (!pArgs->fHideRememberPassword) { // // save "Remember password" // if (fSaveOtherUserInfo) { SaveUserInfo(pArgs, UD_ID_REMEMBER_PWD, (PVOID)&pArgs->fRememberMainPassword); } } if (!pArgs->fHideDialAutomatically) { // // save "Dial automatically..." // if (fSaveOtherUserInfo) { SaveUserInfo(pArgs, UD_ID_NOPROMPT, (PVOID)&pArgs->fDialAutomatically); } } // // Process Password info, if any. If field is hidden, then don't save anything. // HWND hwndPassword = GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT); if (hwndPassword) { BOOL fSavePassword = TRUE; // // We don't want to copy the password into pArgs structure if fSaveUPD isn't true, // because it will be obfuscated in this case. The password is already in the structure // on Win2K+ // if (fSaveUPD) { // // Get the latest password data from the edit control // and obfuscate its contents so that connect actions // can't retrieve it. // GetPasswordFromEdit(pArgs); // fills pArgs->szPassword ObfuscatePasswordEdit(pArgs); // // Check if we have 16 *'s // CmDecodePassword(pArgs->szPassword); if ((0 == lstrcmpU(c_pszSavedPasswordToken, pArgs->szPassword)) && (FALSE == SendMessageU(hwndPassword, EM_GETMODIFY, 0L, 0L))) { // // We have 16 *'s and the user hasn't modified the editbox. This // password is from the RAS cred store, so we don't want to save the 16 *'s // fSavePassword = FALSE; } CmEncodePassword(pArgs->szPassword); } // // For winlogon we need to take the password from the edit box // if (CM_LOGON_TYPE_WINLOGON == pArgs->dwWinLogonType) { GetPasswordFromEdit(pArgs); // fills pArgs->szPassword } // // Update persistent storage // No need to delete the password here as it was done by the calling function // if (pArgs->fRememberMainPassword) { // // If the password has changed, then update storage // Always save password - 303382 // if (fSaveUPD && fSavePassword) { CmDecodePassword(pArgs->szPassword); SaveUserInfo(pArgs, UD_ID_PASSWORD, (PVOID)pArgs->szPassword); CmEncodePassword(pArgs->szPassword); } // // Check DialAutomatically and carry remember state // over to InetPassword if it isn't remembered already. // // Need to check if this is a double-dial scenario. Also need to check if we are // allowed to save UPD, otherwise we don't want to change the state mainly // (pArgs->fRememberInetPassword) // if (pArgs->fDialAutomatically && fSaveUPD && (DOUBLE_DIAL_CONNECTION == pArgs->GetTypeOfConnection())) { // // Carry remember state from DialAutomatically over to // InetPassword if it isn't already remembered. // if (!pArgs->fRememberInetPassword) { pArgs->fRememberInetPassword = TRUE; CmDecodePassword(pArgs->szInetPassword); if (fSavePassword) { SaveUserInfo(pArgs, UD_ID_INET_PASSWORD, (PVOID)pArgs->szInetPassword); } CmEncodePassword(pArgs->szInetPassword); } } } else { // // If we don't have the ras cred store then the password wasn't deleted // so we must deleted by calling this function // if (fSavePassword) // No need to check fSaveUPD, taken care of ras creds store check { if (FALSE == pArgs->bUseRasCredStore) { DeleteUserInfo(pArgs, UD_ID_PASSWORD); } } } if (fSaveUPD) { BOOL fSaveInetPassword = TRUE; // // Check if we have 16 *'s for Internet Password. First, decode and then encode pw // CmDecodePassword(pArgs->szInetPassword); if (0 == lstrcmpU(c_pszSavedPasswordToken, pArgs->szInetPassword)) { // // We have 16 *'s This password is from the RAS cred store, so we don't want to save the 16 *'s // fSaveInetPassword = FALSE; } CmEncodePassword(pArgs->szInetPassword); // // Check to see if we should re-save Internet creds // This needs to be done here in case the user has switched between // global and local credentials using the option buttons while having Internet // credentials set in the Internet Login (CInetPage) property sheet. By switching // the options, the user switched the current credential store // (pArgs->dwCurrentCredentialType) so in order not to lose that data, we need to // re-save the internet creds. Re-saving puts them in the correct (global or local) // ras cred store. // When the username is the same and we saved the main password (SaveUserInfo) // this also saves the password to the Internet creds store // if (pArgs->fUseSameUserName) { if (fSaveInetPassword) { if (pArgs->fRememberMainPassword) { // // Save the UserName into the InetUserName field // Password has been saved when saving UD_ID_PASSWORD. There is a special // case that also saves the main password as the internet password // SaveUserInfo(pArgs, UD_ID_INET_USERNAME, (PVOID)pArgs->szUserName); pArgs->fRememberInetPassword = TRUE; } else { if (FALSE == pArgs->bUseRasCredStore) { DeleteUserInfo(pArgs, UD_ID_INET_PASSWORD); pArgs->fRememberInetPassword = FALSE; } } } } else { if (fSaveInetPassword) { if(pArgs->fRememberInetPassword) { CmDecodePassword(pArgs->szInetPassword); SaveUserInfo(pArgs, UD_ID_INET_PASSWORD, (PVOID)pArgs->szInetPassword); CmEncodePassword(pArgs->szInetPassword); } else { if (FALSE == pArgs->bUseRasCredStore) { DeleteUserInfo(pArgs, UD_ID_INET_PASSWORD); } } } // // Need to save username in either case so we can pre-populate this // SaveUserInfo(pArgs, UD_ID_INET_USERNAME, (PVOID)pArgs->szInetUserName); } } } // // This should be saved in all cases except ICS // if (fSaveOtherUserInfo) { SaveUserInfo(pArgs, UD_ID_REMEMBER_INET_PASSWORD, (PVOID)&pArgs->fRememberInetPassword); } // // Process Domain info, if any // if (GetDlgItem(hwndDlg, IDC_MAIN_DOMAIN_EDIT)) // !pArgs->fHideDomain) { LPTSTR pszDomain = CmGetWindowTextAlloc(hwndDlg,IDC_MAIN_DOMAIN_EDIT); // // save the user info // if (fSaveUPD) { SaveUserInfo(pArgs, UD_ID_DOMAIN, (PVOID)pszDomain); } lstrcpyU(pArgs->szDomain, pszDomain); CmFree(pszDomain); } else { // // In case the domain field is hidden then just re-save what's in the // structure. This needs to be done since all of the credentials might have // been deleted from the ras cred store. // if (fSaveUPD) { SaveUserInfo(pArgs, UD_ID_DOMAIN, (PVOID)pArgs->szDomain); } } return; } //+--------------------------------------------------------------------------- // // Function: SetIniObjectReadWriteFlags // // Synopsis: If the read or write flags are set we need to enable reading and/or // writing to the .CMP file. Each instance of the CIni class may // or may not use the .cmp file. It can also be using the .CMP as either // the primary file or normal file. See InitProfileFromName function // in init.cpp for detailed comments about these instances. // // pArgs->piniProfile - uses .CMP as a regular file // pArgs->piniService - doesn't use .CMP file at all // pArgs->piniBoth - uses .CMP as a primary file // pArgs->piniBothNonFav - uses .CMP as a primary file // // Arguments: pArgs - ptr to ArgsStruct // // Returns: NONE // // History: 02/14/2001 tomkel Created // //---------------------------------------------------------------------------- VOID SetIniObjectReadWriteFlags(ArgsStruct *pArgs) { if (NULL == pArgs) { MYDBGASSERT(pArgs); return; } BOOL fWriteICSInfo = FALSE; BOOL fReadGlobalICSInfo = FALSE; // // Get the read flag // fReadGlobalICSInfo = ((BOOL)(pArgs->dwGlobalUserInfo & CM_GLOBAL_USER_INFO_READ_ICS_DATA) ? TRUE : FALSE); // // Get the write flag. // fWriteICSInfo = ((BOOL)(pArgs->dwGlobalUserInfo & CM_GLOBAL_USER_INFO_WRITE_ICS_DATA) ? TRUE : FALSE); if (fReadGlobalICSInfo || fWriteICSInfo) { LPTSTR pszICSDataReg = BuildICSDataInfoSubKey(pArgs->szServiceName); if (pszICSDataReg) { // // Now that there is a reg key and at least one of the above flags is TRUE, // then we want to set the read and write flags in the classes. By default // they are set to FALSE in the constructors, so we don't have to // explicitly set them if we don't need this functionality. // // Set ICSData reg key // pArgs->piniProfile->SetICSDataPath(pszICSDataReg); pArgs->piniBoth->SetICSDataPath(pszICSDataReg); pArgs->piniBothNonFav->SetICSDataPath(pszICSDataReg); // // Set Write flag since we have a reg key // pArgs->piniProfile->SetWriteICSData(fWriteICSInfo); pArgs->piniBoth->SetWriteICSData(fWriteICSInfo); pArgs->piniBothNonFav->SetWriteICSData(fWriteICSInfo); // // Set Read flag since we have a reg key // pArgs->piniProfile->SetReadICSData(fReadGlobalICSInfo); pArgs->piniBoth->SetReadICSData(fReadGlobalICSInfo); pArgs->piniBothNonFav->SetReadICSData(fReadGlobalICSInfo); } CmFree(pszICSDataReg); } return; } //---------------------------------------------------------------------------- // // Function: TryToDeleteAndSaveCredentials // // Synopsis: Used on Win2K and WinXP+. This function uses the RAS Credential // store to save and delete credentials based on user's selection. // First we need to determine if the user is saving their password. // Then appropriately delete or prompt to delete existing credentials. // If we aren't saving any credentials, then delete all of them. // The special case is if the user is deleting his local credentials // and global credentials exist on the system. Then we have to prompt // if we should delete the global creds as well. // Toward the botton of the function we get the info from the UI. // If the password is 16 *'s then we don't save the password After // getting info from the UI, we save it in the RAS Cred store. // Internet credentials are saved if we are using the same user // name. Otherwise we leave the Internet creds. They were saved // on the Inet properties page. There is a scenario where the user // saved the internet creds on the property page and then switched // the way credentials should be saved (global vs. local) which might cause // the internet password to be stored under in the wrong (global vs. local) // ras store. If the passwords are disjoined (pArgs->fUseSameUserName is FALSE) // there isn't much we can do. // // NOTE: We only want to delete credentials if and only if the existence // flag are set! This is to prevent from deleting mainly global credentials // in a certain profile where global credentials are disabled. // // // Arguments: pArgs - ptr to ArgsStruct // hwndDlg - HWND to dialog // // Returns: NONE // // History: 03/24/2001 tomkel Created // //---------------------------------------------------------------------------- VOID TryToDeleteAndSaveCredentials(ArgsStruct *pArgs, HWND hwndDlg) { if (NULL == pArgs || NULL == hwndDlg) { MYDBGASSERT(pArgs && hwndDlg); return; } // // Check if this is Win2K+ (That's where RAS Creds store is supported) // if (!OS_NT5) { MYDBGASSERT(FALSE); return; } BOOL fSave = FALSE; BOOL fResaveInetUserCreds = FALSE; RASCREDENTIALS rc = {0}; RASCREDENTIALS rcInet={0}; rc.dwSize = sizeof(rc); rcInet.dwSize = sizeof(rcInet); // // See if we want to save the credentials // if (pArgs->fRememberMainPassword) { // // Which password are we saving? // if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { // // Delete User creds w/o asking. No need to check for existence since these // are just user (main & inet) creds. // DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_MAIN, CM_DELETE_SAVED_CREDS_KEEP_GLOBALS, CM_DELETE_SAVED_CREDS_DELETE_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_USER; rc.dwMask = RASCM_DefaultCreds; // // Delete Internet User creds w/o asking // It doesn't matter that we aren't using the same user name // If we are saving globals, then user creds must always be deleted! This applies for main and Internet. // DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_INET, CM_DELETE_SAVED_CREDS_KEEP_GLOBALS, CM_DELETE_SAVED_CREDS_DELETE_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_USER; } else { // // Trying to save User creds. if there is currently no saved per-user password // and the user opts to save the password himself, then ask whether the global // password should be deleted if it exists. // if ((CM_EXIST_CREDS_MAIN_GLOBAL & pArgs->dwExistingCredentials) && !(CM_EXIST_CREDS_MAIN_USER & pArgs->dwExistingCredentials)) { LPTSTR pszTmp = CmLoadString(g_hInst, IDMSG_DELETE_GLOBAL_CREDS); if (pszTmp) { if (IDYES == MessageBoxEx(hwndDlg, pszTmp, pArgs->szServiceName, MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2, LANG_USER_DEFAULT)) { DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_MAIN, CM_DELETE_SAVED_CREDS_DELETE_GLOBALS, CM_DELETE_SAVED_CREDS_DELETE_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_GLOBAL; // // Check for existence before deleting. If they don't exist, no need to // delete them. // if ((CM_EXIST_CREDS_INET_GLOBAL & pArgs->dwExistingCredentials)) { // // Delete Internet Global creds if we are using the same creds // if (pArgs->fUseSameUserName || (FALSE == pArgs->fRememberInetPassword)) { DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_INET, CM_DELETE_SAVED_CREDS_DELETE_GLOBALS, CM_DELETE_SAVED_CREDS_DELETE_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_GLOBAL; } } } } CmFree(pszTmp); } } // // User chose to save password. Cache username, password, and // domain. // fSave = TRUE; rc.dwMask |= RASCM_UserName | RASCM_Password | RASCM_Domain; } else { // // Don't save password // // // Check which option button is currently selected // if (CM_CREDS_USER == pArgs->dwCurrentCredentialType) { // // User is trying to delete his local creds. Delete the user creds. // No need to check if they exist since these are local user creds. // DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_MAIN, CM_DELETE_SAVED_CREDS_KEEP_GLOBALS, CM_DELETE_SAVED_CREDS_KEEP_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_USER; if (pArgs->fUseSameUserName || (FALSE == pArgs->fRememberInetPassword)) { DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_INET, CM_DELETE_SAVED_CREDS_KEEP_GLOBALS, CM_DELETE_SAVED_CREDS_KEEP_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_USER; } // // Check if global creds exist and if so prompt the user asking if he wants // to delete the globals as well // if (CM_EXIST_CREDS_MAIN_GLOBAL & pArgs->dwExistingCredentials) { int iMsgBoxResult = 0; LPTSTR pszTmp = CmLoadString(g_hInst, IDMSG_DELETE_ALL_CREDS); if (pszTmp) { // // Set the default to the 2nd button (NO), thus the user won't // accidentally delete the global creds. // iMsgBoxResult = MessageBoxEx(hwndDlg, pszTmp, pArgs->szServiceName, MB_YESNO|MB_ICONQUESTION|MB_DEFBUTTON2, LANG_USER_DEFAULT); if (IDYES == iMsgBoxResult) { // // Delete global creds // DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_MAIN, CM_DELETE_SAVED_CREDS_DELETE_GLOBALS, CM_DELETE_SAVED_CREDS_DELETE_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_GLOBAL; if (CM_EXIST_CREDS_INET_GLOBAL & pArgs->dwExistingCredentials) { if (pArgs->fUseSameUserName || (FALSE == pArgs->fRememberInetPassword)) { DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_INET, CM_DELETE_SAVED_CREDS_DELETE_GLOBALS, CM_DELETE_SAVED_CREDS_DELETE_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_GLOBAL; } } } } CmFree(pszTmp); pszTmp = NULL; } // // We need to resave username or domain info, even if it existed in case the // user has updated it. // fSave = TRUE; rc.dwMask |= RASCM_UserName | RASCM_Domain; } else { // // Delete both sets of credentials // // // Check if we need to resave User Name and Domain. The call that deletes the // user creds doesn't wipe out User Name and Domain so there is no need to re-save. // if (FALSE == (BOOL)(pArgs->dwExistingCredentials & CM_EXIST_CREDS_MAIN_USER)) { // // Resave the username, and domain since user creds didn't exist // and we want to pre-populate this info next time CM is loaded // fSave = TRUE; rc.dwMask |= RASCM_UserName | RASCM_Domain; } if (CM_EXIST_CREDS_MAIN_GLOBAL & pArgs->dwExistingCredentials) { // // Delete the global credentials. // Note from RAS codebase: Note that we have to delete the global identity // as well because we do not support deleting // just the global password. This is so that // RasSetCredentials can emulate RasSetDialParams. // DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_MAIN, CM_DELETE_SAVED_CREDS_DELETE_GLOBALS, CM_DELETE_SAVED_CREDS_DELETE_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_GLOBAL; } if (CM_EXIST_CREDS_INET_GLOBAL & pArgs->dwExistingCredentials) { if (pArgs->fUseSameUserName || (FALSE == pArgs->fRememberInetPassword)) { DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_INET, CM_DELETE_SAVED_CREDS_DELETE_GLOBALS, CM_DELETE_SAVED_CREDS_DELETE_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_GLOBAL; // // If we don't have Inet user creds then we need to cache the username for Inet creds // if (FALSE == (BOOL)(CM_EXIST_CREDS_INET_USER & pArgs->dwExistingCredentials)) { fResaveInetUserCreds = TRUE; } } } // // Delete the password saved per-user. Keep the user name // and domain saved, however. // if (CM_EXIST_CREDS_MAIN_USER & pArgs->dwExistingCredentials) { DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_MAIN, CM_DELETE_SAVED_CREDS_KEEP_GLOBALS, CM_DELETE_SAVED_CREDS_KEEP_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_MAIN_USER; } if (CM_EXIST_CREDS_INET_USER & pArgs->dwExistingCredentials) { if (pArgs->fUseSameUserName || (FALSE == pArgs->fRememberInetPassword)) { DeleteSavedCredentials(pArgs, CM_CREDS_TYPE_INET, CM_DELETE_SAVED_CREDS_KEEP_GLOBALS, CM_DELETE_SAVED_CREDS_KEEP_IDENTITY); pArgs->dwExistingCredentials &= ~CM_EXIST_CREDS_INET_USER; } } } } // // Gets the info from the UI into pArgs and copy them into the RASCREDENTIALS structure // GetUserInfoFromDialog(pArgs, hwndDlg, &rc); // // See if we need to save anything // if (fSave) { LPTSTR pszConnectoid = GetRasConnectoidName(pArgs, pArgs->piniService, FALSE); DWORD dwCurrentMask = rc.dwMask; DWORD dwInetCurrentMask = rc.dwMask & ~RASCM_Domain; // Don't need domain info if (pszConnectoid && pArgs->rlsRasLink.pfnSetCredentials) { DWORD dwRet = (DWORD)-1; // Some non ERROR_SUCCESS value DWORD dwRetInet = (DWORD)-1; // Some non ERROR_SUCCESS value LPTSTR pszPhoneBook = pArgs->pszRasPbk; LPTSTR pszPrivatePhoneBook = CreateRasPrivatePbk(pArgs); CopyMemory((LPVOID)&rcInet, (LPVOID)&rc, sizeof(rcInet)); // // Save the creds // dwRet = pArgs->rlsRasLink.pfnSetCredentials(pszPhoneBook, pszConnectoid, &rc, FALSE); if (ERROR_CANNOT_FIND_PHONEBOOK_ENTRY == dwRet) { // // Then the phonebook entry doesn't exist yet, lets create it. // LPRASENTRY pRasEntry = (LPRASENTRY)CmMalloc(sizeof(RASENTRY)); if (pRasEntry && pArgs->rlsRasLink.pfnSetEntryProperties) { pRasEntry->dwSize = sizeof(RASENTRY); dwRet = pArgs->rlsRasLink.pfnSetEntryProperties(pszPhoneBook, pszConnectoid, pRasEntry, pRasEntry->dwSize, NULL, 0); // // Lets try to set the credentials one more time ... // if (ERROR_SUCCESS == dwRet) { // // dwMask needs to be reassigned, the previous call modified it // rc.dwMask = dwCurrentMask; dwRet = pArgs->rlsRasLink.pfnSetCredentials(pszPhoneBook, pszConnectoid, &rc, FALSE); } CmFree(pRasEntry); } } // // Now try to save Internet creds // if (ERROR_SUCCESS == dwRet && pszPrivatePhoneBook) { // // If we aren't using the credentials for main and Inet, then there // is no need to resave Internet credentials, because they were saved on // the Inet-Dialog page and they weren't deleted above. // if (pArgs->fUseSameUserName) { // // dwMask needs to be reassigned, the previous call modified it // rcInet.dwMask = dwInetCurrentMask; dwRetInet = pArgs->rlsRasLink.pfnSetCredentials(pszPrivatePhoneBook, pszConnectoid, &rcInet, FALSE); } else { if (fResaveInetUserCreds) { rcInet.dwMask = dwInetCurrentMask; dwRetInet = pArgs->rlsRasLink.pfnSetCredentials(pszPrivatePhoneBook, pszConnectoid, &rcInet, FALSE); } if (pArgs->fDialAutomatically && (DOUBLE_DIAL_CONNECTION == pArgs->GetTypeOfConnection())) { // // Carry remember state from DialAutomatically over to // InetPassword if it isn't already remembered. // if (FALSE == pArgs->fRememberInetPassword) { pArgs->fRememberInetPassword = TRUE; CmDecodePassword(pArgs->szInetPassword); // // Compare to 16 *'s. We don't want to resave if we have 16 *'s // otherwise the user will get an auth-retry. // if (0 != lstrcmpU(c_pszSavedPasswordToken, pArgs->szInetPassword)) { // // No need to save the domain // rcInet.dwMask = dwInetCurrentMask; lstrcpyU(rcInet.szUserName, pArgs->szInetUserName); lstrcpyU(rcInet.szPassword, pArgs->szInetPassword); dwRetInet = pArgs->rlsRasLink.pfnSetCredentials(pszPrivatePhoneBook, pszConnectoid, &rcInet, FALSE); } CmEncodePassword(pArgs->szInetPassword); } } } } if ((ERROR_CANNOT_FIND_PHONEBOOK_ENTRY == dwRetInet) && pszPrivatePhoneBook) { // // Then the phonebook entry doesn't exist yet, lets create it. // LPRASENTRY pRasEntry = (LPRASENTRY)CmMalloc(sizeof(RASENTRY)); if (pRasEntry && pArgs->rlsRasLink.pfnSetEntryProperties) { pRasEntry->dwSize = sizeof(RASENTRY); dwRetInet = pArgs->rlsRasLink.pfnSetEntryProperties(pszPrivatePhoneBook, pszConnectoid, pRasEntry, pRasEntry->dwSize, NULL, 0); // // Lets try to set the credentials one more time ... // if (ERROR_SUCCESS == dwRetInet) { // // dwMask needs to be reassigned, the previous call modifies the mask // rcInet.dwMask = dwInetCurrentMask; dwRetInet = pArgs->rlsRasLink.pfnSetCredentials(pszPrivatePhoneBook, pszConnectoid, &rcInet, FALSE); } CmFree(pRasEntry); } } if (ERROR_SUCCESS == dwRet) { // // Only set the existance flags if we are saving the password and everything // succeeded // if (pArgs->fRememberMainPassword) { if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType) { pArgs->dwExistingCredentials |= CM_EXIST_CREDS_MAIN_GLOBAL; if (pArgs->fUseSameUserName && (ERROR_SUCCESS == dwRetInet)) { pArgs->dwExistingCredentials |= CM_EXIST_CREDS_INET_GLOBAL; } } else { pArgs->dwExistingCredentials |= CM_EXIST_CREDS_MAIN_USER; if (pArgs->fUseSameUserName && (ERROR_SUCCESS == dwRetInet)) { pArgs->dwExistingCredentials |= CM_EXIST_CREDS_INET_USER; } } } } CmFree(pszPrivatePhoneBook); } CmFree(pszConnectoid); } ZeroMemory(rc.szPassword, sizeof(rc.szPassword)); ZeroMemory(rcInet.szPassword, sizeof(rcInet.szPassword)); return; } //---------------------------------------------------------------------------- // // Function: GetUserInfoFromDialog // // Synopsis: Gets the user information from the editboxes into pArgs // structure. Then it copies the info into rascredentials // structure. If the password is 16 *'s then we clear // the password mask in the rascredentials in order not to save // the password. // // Arguments: pArgs - ptr to ArgsStruct // hwndDlg - HWND to dialog // prc - [IN/OUT] rascredentials structure // // Returns: NONE // // History: 03/24/2001 tomkel Created // //---------------------------------------------------------------------------- VOID GetUserInfoFromDialog(ArgsStruct *pArgs, HWND hwndDlg, RASCREDENTIALS *prc) { if (NULL == pArgs || NULL == hwndDlg || NULL == prc) { MYDBGASSERT(pArgs && hwndDlg && prc); return; } // // Process Password info, if any. // HWND hwndPassword = GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT); if (hwndPassword) { // // Get the latest password data from the edit control // and obfuscate its contents so that connect actions // can't retrieve it. // GetPasswordFromEdit(pArgs); // fills pArgs->szPassword ObfuscatePasswordEdit(pArgs); // sets *'s into the password edit box // // Check if we have 16 *'s // CmDecodePassword(pArgs->szPassword); if ((0 == lstrcmpU(c_pszSavedPasswordToken, pArgs->szPassword)) && (FALSE == SendMessageU(hwndPassword, EM_GETMODIFY, 0L, 0L))) { // // We have 16 *'s and the user hasn't modified the editbox. This // password is from the RAS cred store, so we don't want to save the 16 *'s // prc->dwMask &= ~RASCM_Password; } CmEncodePassword(pArgs->szPassword); } // // Process UserName info, if any // HWND hwndUserName = GetDlgItem(hwndDlg, IDC_MAIN_USERNAME_EDIT); if (hwndUserName) { LPTSTR pszUsername = CmGetWindowTextAlloc(hwndDlg, IDC_MAIN_USERNAME_EDIT); lstrcpyU(pArgs->szUserName, pszUsername); CmFree(pszUsername); } // // Process Domain info, if any // HWND hwndDomain = GetDlgItem(hwndDlg, IDC_MAIN_DOMAIN_EDIT); if (hwndDomain) { LPTSTR pszDomain = CmGetWindowTextAlloc(hwndDlg,IDC_MAIN_DOMAIN_EDIT); lstrcpyU(pArgs->szDomain, pszDomain); CmFree(pszDomain); } // // This needs to be separate because in some cases // the editboxes will not exist on the dialog, but we still need to save the info // from the pArgs structure into RASCREDENTIALS. // lstrcpyU(prc->szUserName, pArgs->szUserName); lstrcpyU(prc->szDomain, pArgs->szDomain); CmDecodePassword(pArgs->szPassword); lstrcpyU(prc->szPassword, pArgs->szPassword); CmEncodePassword(pArgs->szPassword); } //---------------------------------------------------------------------------- // // Function: SwitchToLocalCreds // // Synopsis: Clear the password, but only if it wasn't recently modified // only then we can reuse and resave it. That's because when // we switch credential stores, the value of the szPassword // is what was read from the RAS cred store (16 *'s). It doesn't // make sense to save this value into a new user RAS creds store. If the // password already existed there, then it's fine. // In case the user modified the password text box and then decided // to swich, the modification flag will be on, so we'll assume that the // user entered a valid password and that it wasn't read in from the // creds store. // The actual deletion of credential happnes once the user clicks // the connect button. Here we just clear things out of memory // and update the UI. We also need to update the remember Internet // flag based on if the Internet credential exist. This is so the // UI stays consistent with what credentials are loaded in memory. // // Arguments: pArgs - ptr to ArgsStruct // hwndDlg - HWND to dialog // fSwitchToGlobal - used to ignore the check which credential // store is currently active // // Returns: NONE // // History: 03/24/2001 tomkel Created // //---------------------------------------------------------------------------- VOID SwitchToLocalCreds(ArgsStruct *pArgs, HWND hwndDlg, BOOL fSwitchToLocal) { if (NULL == pArgs || NULL == hwndDlg) { return; } // // Switching to using Single-User credentials // // // Check that previously the default was the Global creds store // if (CM_CREDS_GLOBAL == pArgs->dwCurrentCredentialType || fSwitchToLocal) { pArgs->dwCurrentCredentialType = CM_CREDS_USER; HWND hwndTemp = GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT); BOOL fPWChanged = FALSE; if (hwndTemp) { // // Don't use Edit_GetModify. This needs need to run on Win9x so call // SendMessageU // fPWChanged = (BOOL) SendMessageU(hwndTemp, EM_GETMODIFY, 0L, 0L); if (FALSE == fPWChanged) { pArgs->fIgnoreChangeNotification = TRUE; CmWipePassword(pArgs->szPassword); SetDlgItemTextU(hwndDlg, IDC_MAIN_PASSWORD_EDIT, TEXT("")); pArgs->fIgnoreChangeNotification = FALSE; } } if (FALSE == fPWChanged) { // // Only if Password field didn't change // if (OS_NT51) { // // Wipe the Internet password - since we are switching from globals // or we are using the same user name the Inet password will get re-populated // from the main password, otherwise the user needs to set this password in // the InetDialog. // CmWipePassword(pArgs->szInetPassword); pArgs->fRememberInetPassword = FALSE; // // Only reload if main user creds exist // if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_MAIN_USER) { if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_INET_USER) { ReloadCredentials(pArgs, hwndDlg, CM_CREDS_TYPE_BOTH); pArgs->fRememberInetPassword = TRUE; } else { ReloadCredentials(pArgs, hwndDlg, CM_CREDS_TYPE_MAIN); } } else { if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_INET_USER) { ReloadCredentials(pArgs, hwndDlg, CM_CREDS_TYPE_INET); pArgs->fRememberInetPassword = TRUE; } else { pArgs->fRememberInetPassword = FALSE; } } } else { ReloadCredentials(pArgs, hwndDlg, CM_CREDS_TYPE_BOTH); } } else { if (OS_NT51) { if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_INET_USER) { ReloadCredentials(pArgs, hwndDlg, CM_CREDS_TYPE_INET); pArgs->fRememberInetPassword = TRUE; } else { pArgs->fRememberInetPassword = FALSE; } } else { ReloadCredentials(pArgs, hwndDlg, CM_CREDS_TYPE_INET); } } } } //---------------------------------------------------------------------------- // // Function: SwitchToGlobalCreds // // Synopsis: Clear the password and reload the credentials if they exist. // Otherwise we clear the password if it hasn't been modified by // the user. // // Arguments: pArgs - ptr to ArgsStruct // hwndDlg - HWND to dialog // fSwitchToGlobal - used to ignore the check which credential // store is currently active // // Returns: NONE // // History: 03/24/2001 tomkel Created // //---------------------------------------------------------------------------- VOID SwitchToGlobalCreds(ArgsStruct *pArgs, HWND hwndDlg, BOOL fSwitchToGlobal) { if (NULL == pArgs || NULL == hwndDlg) { return; } // // This should only be called on WinXP+ // if (!OS_NT51) { MYDBGASSERT(FALSE); return; } // // Switching to using Global credentials // // // Check that previously the default was the User creds store // if (CM_CREDS_USER == pArgs->dwCurrentCredentialType || fSwitchToGlobal) { pArgs->dwCurrentCredentialType = CM_CREDS_GLOBAL; if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_MAIN_GLOBAL) { CmWipePassword(pArgs->szPassword); CmWipePassword(pArgs->szInetPassword); pArgs->fRememberInetPassword = FALSE; // // Globals exist // if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_INET_GLOBAL) { // // Both exist - reload both // ReloadCredentials(pArgs, hwndDlg, CM_CREDS_TYPE_BOTH); pArgs->fRememberInetPassword = TRUE; } else { // // User Globals - exist, reload // Internet Globals - don't exist, clear password // ReloadCredentials(pArgs, hwndDlg, CM_CREDS_TYPE_MAIN); } } else { HWND hwndPassword = GetDlgItem(hwndDlg, IDC_MAIN_PASSWORD_EDIT); pArgs->fIgnoreChangeNotification = TRUE; CmWipePassword(pArgs->szInetPassword); pArgs->fRememberInetPassword = FALSE; if (pArgs->dwExistingCredentials & CM_EXIST_CREDS_INET_GLOBAL) { // // User Globals - don't exist - clear password // Internet Globals - exist - reload // RefreshCredentialInfo(pArgs, CM_CREDS_TYPE_INET); // // In case user inet creds didn't exist, we should // pArgs->fRememberInetPassword = TRUE; } // // Clear the main password only if it wasn't recently modified // if (hwndPassword) { if (FALSE == SendMessageU(hwndPassword, EM_GETMODIFY, 0L, 0L)) { CmWipePassword(pArgs->szPassword); SetDlgItemTextU(hwndDlg, IDC_MAIN_PASSWORD_EDIT, TEXT("")); } } pArgs->fIgnoreChangeNotification = FALSE; } } } //---------------------------------------------------------------------------- // // Function: ReloadCredentials // // Synopsis: Wrapper to reload credentials into the editboxes // // Arguments: pArgs - ptr to ArgsStruct // hwndDlg - HWND to dialog // dwWhichCredType - type of credential to reload // // Returns: NONE // // History: 03/24/2001 tomkel Created // //---------------------------------------------------------------------------- VOID ReloadCredentials(ArgsStruct *pArgs, HWND hwndDlg, DWORD dwWhichCredType) { if (NULL == pArgs || NULL == hwndDlg) { MYDBGASSERT(pArgs && hwndDlg); return; } pArgs->fIgnoreChangeNotification = TRUE; RefreshCredentialInfo(pArgs, dwWhichCredType); SetMainDlgUserInfo(pArgs, hwndDlg); pArgs->fIgnoreChangeNotification = FALSE; } //---------------------------------------------------------------------------- // // Function: VerifyAdvancedTabSettings // // Synopsis: Verifies and possibly modifed the connection's ICF/ICS settings // based on what was configured in the .cms file. These functions // depend on the hnetcfg objects and private/internal interfaces. // We got them from the homenet team. // Some parts of the code were taken from: // nt\net\homenet\config\dll\saui.cpp // // Arguments: pArgs - ptr to ArgsStruct // // Returns: NONE // // History: 04/26/2001 tomkel Created // //---------------------------------------------------------------------------- VOID VerifyAdvancedTabSettings(ArgsStruct *pArgs) { #ifndef _WIN64 HRESULT hr; IHNetConnection *pHNetConn = NULL; IHNetCfgMgr *pHNetCfgMgr = NULL; INetConnectionUiUtilities* pncuu = NULL; BOOL fCOMInitialized = FALSE; BOOL fEnableICF = FALSE; BOOL fDisableICS = FALSE; BOOL fAllowUserToModifySettings = TRUE; if (OS_NT51) { CMTRACE(TEXT("VerifyAdvancedTabSettings()")); // // Check rights - taken from saui.cpp // if (FALSE == IsAdmin()) { return; } fEnableICF = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryEnableICF, FALSE); fDisableICS = pArgs->piniService->GPPB(c_pszCmSection, c_pszCmEntryDisableICS, FALSE); if (fEnableICF || fDisableICS) { hr = CoInitialize(NULL); if (S_OK == hr) { CMTRACE(TEXT("VerifyAdvancedTabSettings - Correctly Initialized COM.")); fCOMInitialized = TRUE; } else if (S_FALSE == hr) { CMTRACE(TEXT("VerifyAdvancedTabSettings - This concurrency model is already initialized. CoInitialize returned S_FALSE.")); fCOMInitialized = TRUE; hr = S_OK; } else if (RPC_E_CHANGED_MODE == hr) { CMTRACE1(TEXT("VerifyAdvancedTabSettings - Using different concurrency model. Did not initialize COM - RPC_E_CHANGED_MODE. hr=0x%x"), hr); hr = S_OK; } else { CMTRACE1(TEXT("VerifyAdvancedTabSettings - Failed to Initialized COM. hr=0x%x"), hr); } if (SUCCEEDED(hr)) { // // Check user permissions. Needed to initialize COM first // Check if ZAW is denying access to the Shared Access UI - taken from saui.cpp // hr = HrCreateNetConnectionUtilities(&pncuu); if (SUCCEEDED(hr) && pncuu) { fEnableICF = (BOOL)(fEnableICF && pncuu->UserHasPermission(NCPERM_PersonalFirewallConfig)); fDisableICS = (BOOL)(fDisableICS && pncuu->UserHasPermission(NCPERM_ShowSharedAccessUi)); if ((FALSE == fEnableICF) && (FALSE == fDisableICS)) { goto done; } } // // Create the home networking configuration manager // hr = CoCreateInstance(CLSID_HNetCfgMgr, NULL, CLSCTX_ALL, IID_IHNetCfgMgr, (void**)&pHNetCfgMgr); if (SUCCEEDED(hr)) { // // Convert the entry to an IHNetConnection // CMTRACE(TEXT("VerifyAdvancedTabSettings - Created CLSID_HNetCfgMgr object.")); GUID *pGuid = NULL; LPRASENTRY pRasEntry = MyRGEP(pArgs->pszRasPbk, pArgs->szServiceName, &pArgs->rlsRasLink); if (pRasEntry && sizeof(RASENTRY_V501) >= pRasEntry->dwSize) { // // Get the pGuid value // pGuid = &(((LPRASENTRY_V501)pRasEntry)->guidId); hr = pHNetCfgMgr->GetIHNetConnectionForGuid(pGuid, FALSE, TRUE, &pHNetConn); if (SUCCEEDED(hr) && pHNetConn) { if (fEnableICF) { EnableInternetFirewall(pHNetConn); } if (fDisableICS) { DisableSharing(pHNetConn); } } else { CMTRACE1(TEXT("VerifyAdvancedTabSettings() - Call to pHNetCfgMgr->GetIHNetConnectionForGuid returned an error. hr=0x%x"), hr); } } else { CMTRACE(TEXT("VerifyAdvancedTabSettings - Failed to LoadRAS Entry.")); } CmFree(pRasEntry); pRasEntry = NULL; } else { CMTRACE(TEXT("VerifyAdvancedTabSettings - Failed to create CLSID_HNetCfgMgr object.")); } } } done: // // Clean up and Uninitilize COM // if (pHNetConn) { pHNetConn->Release(); pHNetConn = NULL; } if (pHNetCfgMgr) { pHNetCfgMgr->Release(); pHNetCfgMgr = NULL; } if (pncuu) { pncuu->Release(); pncuu = NULL; } if (fCOMInitialized) { CoUninitialize(); } } #endif // _WIN64 } //---------------------------------------------------------------------------- // // Function: FindINetConnectionByGuid // // Synopsis: Retrieves the INetConnection that corresponds to the given GUID. // // Arguments: pGuid - the guid of the connection // ppNetCon - receives the interface // // Returns: HRESULT // // History: 04/26/2001 tomkel Taken & modified from nt\net\homenet\config\dll\hnapi.cpp // //---------------------------------------------------------------------------- HRESULT FindINetConnectionByGuid(GUID *pGuid, INetConnection **ppNetCon) { HRESULT hr; INetConnectionManager *pManager = NULL; IEnumNetConnection *pEnum = NULL; INetConnection *pConn = NULL; if (NULL == ppNetCon) { hr = E_INVALIDARG; } else if (NULL == pGuid) { hr = E_POINTER; } else { // // Get the net connections manager // hr = CoCreateInstance( CLSID_ConnectionManager, NULL, CLSCTX_ALL, IID_INetConnectionManager, (void**)&pManager); if (S_OK == hr) { // // Get the enumeration of connections // SetProxyBlanket(pManager); hr = pManager->EnumConnections(NCME_DEFAULT, &pEnum); pManager->Release(); } if (S_OK == hr) { // // Search for the connection with the correct guid // ULONG ulCount; BOOLEAN fFound = FALSE; SetProxyBlanket(pEnum); do { NETCON_PROPERTIES *pProps = NULL; hr = pEnum->Next(1, &pConn, &ulCount); if (SUCCEEDED(hr) && 1 == ulCount) { SetProxyBlanket(pConn); hr = pConn->GetProperties(&pProps); if (S_OK == hr) { if (IsEqualGUID(pProps->guidId, *pGuid)) { fFound = TRUE; *ppNetCon = pConn; (*ppNetCon)->AddRef(); } if (pProps) { CoTaskMemFree (pProps->pszwName); CoTaskMemFree (pProps->pszwDeviceName); CoTaskMemFree (pProps); } } pConn->Release(); } } while (FALSE == fFound && SUCCEEDED(hr) && 1 == ulCount); // // Normalize hr // hr = (fFound ? S_OK : E_FAIL); pEnum->Release(); } } return hr; } //---------------------------------------------------------------------------- // // Function: SetProxyBlanket // // Synopsis: Sets the standard COM security settings on the proxy for an object. // // Arguments: pUnk - the object to set the proxy blanket on // // Returns: None. Even if the CoSetProxyBlanket calls fail, pUnk remains // in a usable state. Failure is expected in certain contexts, such // as when, for example, we're being called w/in the netman process -- // in this case, we have direct pointers to the netman objects, instead // of going through a proxy. // // History: 04/26/2001 tomkel Taken & modified from nt\net\homenet\config\dll\hnapi.cpp // //---------------------------------------------------------------------------- VOID SetProxyBlanket(IUnknown *pUnk) { HRESULT hr; if (NULL == pUnk) { return; } hr = CoSetProxyBlanket( pUnk, RPC_C_AUTHN_WINNT, // use NT default security RPC_C_AUTHZ_NONE, // use NT default authentication NULL, // must be null if default RPC_C_AUTHN_LEVEL_CALL, // call RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // use process token EOAC_NONE ); if (SUCCEEDED(hr)) { IUnknown * pUnkSet = NULL; hr = pUnk->QueryInterface(&pUnkSet); if (SUCCEEDED(hr)) { hr = CoSetProxyBlanket( pUnkSet, RPC_C_AUTHN_WINNT, // use NT default security RPC_C_AUTHZ_NONE, // use NT default authentication NULL, // must be null if default RPC_C_AUTHN_LEVEL_CALL, // call RPC_C_IMP_LEVEL_IMPERSONATE, NULL, // use process token EOAC_NONE ); pUnkSet->Release(); } } } //---------------------------------------------------------------------------- // // Function: EnableInternetFirewall // // Synopsis: Taken from : CNetSharingConfiguration::EnableInternetFirewall // This is part of the internal api. // // Arguments: pHNetConn - HNetConnection // // Returns: None. // // History: 04/26/2001 tomkel Taken & modified from nt\net\homenet\config\dll\hnapi.cpp // //---------------------------------------------------------------------------- VOID EnableInternetFirewall(IHNetConnection *pHNetConn) { HRESULT hr = S_FALSE; BOOLEAN bEnabled = FALSE; if (NULL == pHNetConn) { return; } hr = InternalGetFirewallEnabled(pHNetConn, &bEnabled); if (SUCCEEDED(hr) && !bEnabled) { IHNetFirewalledConnection* pFirewalledConnection = NULL; hr = pHNetConn->Firewall(&pFirewalledConnection); if (SUCCEEDED(hr)) { if (pFirewalledConnection) { pFirewalledConnection->Release(); pFirewalledConnection = NULL; } } } } //---------------------------------------------------------------------------- // // Function: InternalGetFirewallEnabled // // Synopsis: Taken from : CNetSharingConfiguration::EnableInternetFirewall // // Arguments: pHNetConnection - HNetConnection // pbEnabled - [out] whether the Firewall is enabled // // Returns: HRESULT // // History: 04/26/2001 tomkel Taken & modified from nt\net\homenet\config\dll\hnapi.cpp // //---------------------------------------------------------------------------- HRESULT InternalGetFirewallEnabled(IHNetConnection *pHNetConnection, BOOLEAN *pbEnabled) { HRESULT hr; HNET_CONN_PROPERTIES* pProps = NULL; if (NULL == pHNetConnection) { hr = E_INVALIDARG; } else if (NULL == pbEnabled) { hr = E_POINTER; } else { *pbEnabled = FALSE; hr = pHNetConnection->GetProperties(&pProps); if (SUCCEEDED(hr)) { if (pProps->fFirewalled) { *pbEnabled = TRUE; } CoTaskMemFree(pProps); } } return hr; } //---------------------------------------------------------------------------- // // Function: DisableSharing // // Synopsis: Taken from : CNetSharingConfiguration::EnableInternetFirewall // // Arguments: pHNetConn - HNetConnection // // Returns: HRESULT // // History: 04/26/2001 tomkel Taken & modified from nt\net\homenet\config\dll\hnapi.cpp // //---------------------------------------------------------------------------- STDMETHODIMP DisableSharing(IHNetConnection *pHNetConn) { HRESULT hr; BOOLEAN bEnabled = FALSE; SHARINGCONNECTIONTYPE Type; if (NULL == pHNetConn) { return E_INVALIDARG; } hr = InternalGetSharingEnabled(pHNetConn, &bEnabled, &Type); if (SUCCEEDED(hr) && bEnabled ) { switch(Type) { case ICSSHARINGTYPE_PUBLIC: { IHNetIcsPublicConnection* pPublicConnection = NULL; hr = pHNetConn->GetControlInterface( __uuidof(IHNetIcsPublicConnection), reinterpret_cast(&pPublicConnection) ); if (SUCCEEDED(hr)) { hr = pPublicConnection->Unshare(); if (pPublicConnection) { pPublicConnection->Release(); pPublicConnection = NULL; } } } break; case ICSSHARINGTYPE_PRIVATE: { IHNetIcsPrivateConnection* pPrivateConnection = NULL; hr = pHNetConn->GetControlInterface( __uuidof(IHNetIcsPrivateConnection), reinterpret_cast(&pPrivateConnection) ); if (SUCCEEDED(hr)) { hr = pPrivateConnection->RemoveFromIcs(); if (pPrivateConnection) { pPrivateConnection->Release(); pPrivateConnection = NULL; } } } break; default: hr = E_UNEXPECTED; } } return hr; } //---------------------------------------------------------------------------- // // Function: InternalGetSharingEnabled // // Synopsis: Returns whether sharing is enabled on a given connection // // Arguments: pHNetConnection - HNetConnection // pbEnabled - [out] returns the value // pType - type of connection // // Returns: HRESULT // // History: 04/26/2001 tomkel Taken & modified from nt\net\homenet\config\dll\hnapi.cpp // //---------------------------------------------------------------------------- HRESULT InternalGetSharingEnabled(IHNetConnection *pHNetConnection, BOOLEAN *pbEnabled, SHARINGCONNECTIONTYPE* pType) { HRESULT hr; HNET_CONN_PROPERTIES* pProps; if (NULL == pHNetConnection) { hr = E_INVALIDARG; } else if ((NULL == pbEnabled) || (NULL == pType)) { hr = E_POINTER; } else { *pbEnabled = FALSE; *pType = ICSSHARINGTYPE_PUBLIC; hr = pHNetConnection->GetProperties(&pProps); if (SUCCEEDED(hr)) { if (pProps->fIcsPublic) { *pbEnabled = TRUE; *pType = ICSSHARINGTYPE_PUBLIC; } else if (pProps->fIcsPrivate) { *pbEnabled = TRUE; *pType = ICSSHARINGTYPE_PRIVATE; } CoTaskMemFree(pProps); } } return hr; } //---------------------------------------------------------------------------- // // Function: HrCreateNetConnectionUtilities // // Synopsis: Returns the pointer to the connection ui utilities object // // Arguments: ppncuu - pointer to INetConnectionUiUtilities object // // Returns: HRESULT // // History: 04/26/2001 tomkel Taken & modified from nt\net\homenet\config\dll\saui.cpp // //---------------------------------------------------------------------------- HRESULT APIENTRY HrCreateNetConnectionUtilities(INetConnectionUiUtilities ** ppncuu) { HRESULT hr = E_INVALIDARG; if (ppncuu) { hr = CoCreateInstance (CLSID_NetConnectionUiUtilities, NULL, CLSCTX_INPROC_SERVER, IID_INetConnectionUiUtilities, (void**)ppncuu); } return hr; } //+---------------------------------------------------------------------------- // // Function: IsMemberOfGroup // // Synopsis: This function return TRUE if the current user is a member of // the passed and FALSE passed in Group RID. // // Arguments: DWORD dwGroupRID -- the RID of the group to check membership of // BOOL bUseBuiltinDomainRid -- whether the SECURITY_BUILTIN_DOMAIN_RID // RID should be used to build the Group // SID // // Returns: BOOL - TRUE if the user is a member of the specified group // // History: quintinb Shamelessly stolen from MSDN 02/19/98 // quintinb Reworked and renamed 06/18/99 // to apply to more than just Admins // quintinb Rewrote to use CheckTokenMemberShip 08/18/99 // since the MSDN method was no longer // correct on NT5 -- 389229 // tomkel Taken from cmstp and modified for use 05/09/2001 // here // //+---------------------------------------------------------------------------- BOOL IsMemberOfGroup(DWORD dwGroupRID, BOOL bUseBuiltinDomainRid) { PSID psidGroup = NULL; SID_IDENTIFIER_AUTHORITY siaNtAuthority = SECURITY_NT_AUTHORITY; BOOL bSuccess = FALSE; if (OS_NT5) { // // Make a SID for the Group we are checking for, Note that we if we need the Built // in Domain RID (for Groups like Administrators, PowerUsers, Users, etc) // then we will have two entries to pass to AllocateAndInitializeSid. Otherwise, // (for groups like Authenticated Users) we will only have one. // BYTE byNum; DWORD dwFirstRID; DWORD dwSecondRID; if (bUseBuiltinDomainRid) { byNum = 2; dwFirstRID = SECURITY_BUILTIN_DOMAIN_RID; dwSecondRID = dwGroupRID; } else { byNum = 1; dwFirstRID = dwGroupRID; dwSecondRID = 0; } if (AllocateAndInitializeSid(&siaNtAuthority, byNum, dwFirstRID, dwSecondRID, 0, 0, 0, 0, 0, 0, &psidGroup)) { // // Now we need to dynamically load the CheckTokenMemberShip API from // advapi32.dll since it is a Win2k only API. // HMODULE hAdvapi = LoadLibraryExU(TEXT("advapi32.dll"), NULL, 0); if (hAdvapi) { typedef BOOL (WINAPI *pfnCheckTokenMembershipSpec)(HANDLE, PSID, PBOOL); pfnCheckTokenMembershipSpec pfnCheckTokenMembership; pfnCheckTokenMembership = (pfnCheckTokenMembershipSpec)GetProcAddress(hAdvapi, "CheckTokenMembership"); if (pfnCheckTokenMembership) { // // Check to see if the user is actually a member of the group in question // if (!(pfnCheckTokenMembership)(NULL, psidGroup, &bSuccess)) { bSuccess = FALSE; CMASSERTMSG(FALSE, TEXT("CheckTokenMemberShip Failed.")); } } else { CMASSERTMSG(FALSE, TEXT("IsMemberOfGroup -- GetProcAddress failed for CheckTokenMemberShip")); } } else { CMASSERTMSG(FALSE, TEXT("IsMemberOfGroup -- Unable to get the module handle for advapi32.dll")); } FreeSid (psidGroup); if (hAdvapi) { FreeLibrary(hAdvapi); } } } return bSuccess; } //+---------------------------------------------------------------------------- // // Function: IsAdmin // // Synopsis: Check to see if the user is a member of the Administrators group // or not. // // Arguments: None // // Returns: BOOL - TRUE if the current user is an Administrator // // History: quintinb Created Header 8/18/99 // tomkel Taken from cmstp 05/09/2001 // //+---------------------------------------------------------------------------- BOOL IsAdmin(VOID) { return IsMemberOfGroup(DOMAIN_ALIAS_RID_ADMINS, TRUE); // TRUE == bUseBuiltinDomainRid }