Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

13326 lines
416 KiB

//+----------------------------------------------------------------------------
//
// 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; nPhoneIdx<MAX_PHONE_NUMBERS; nPhoneIdx++)
{
LPTSTR pszDUN = NULL;
LPTSTR pszDesc = NULL;
LPTSTR pszPhoneBookFile = NULL;
LPTSTR pszRegionName = NULL;
LPTSTR pszServiceType = NULL;
LPTSTR pszCanonical = NULL;
DWORD dwCountryID;
DWORD dwPhoneInfoFlags;
//
// get phone number by index; Phone0, Phone1 , etc...
//
LPTSTR pszPhone = GetPhoneByIdx(pArgs,
nPhoneIdx,
&pszDesc,
&pszDUN,
&dwCountryID,
&pszRegionName,
&pszServiceType,
&pszPhoneBookFile,
&pszCanonical,
&dwPhoneInfoFlags);
(void)StringCchCopyEx(pArgs->aDialInfo[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; nPhoneIdx<MAX_PHONE_NUMBERS; nPhoneIdx++)
{
//
// If dialing rules is disabled, then just use the NonCanonical #
//
if (pArgs->fNoDialingRules)
{
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<void**>(&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<void**>(&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
}