13327 lines
416 KiB
C++
13327 lines
416 KiB
C++
//+----------------------------------------------------------------------------
|
|
//
|
|
// 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
|
|
}
|
|
|