Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4921 lines
193 KiB

//+----------------------------------------------------------------------------
//
// File: netsettings.cpp
//
// Module: CMAK.EXE
//
// Synopsis: Code dealing with network settings (DUN settings).
//
// Copyright (c) 2000 Microsoft Corporation
//
// Author: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
#include "cmmaster.h"
#include <windowsx.h>
extern BOOL g_bNewProfile;
#define CM_CMAK 1
#include "cm_eap.cpp"
//+----------------------------------------------------------------------------
//
// Function: ReadDunServerSettings
//
// Synopsis: Reads in all of the settings from the Server DUN setting section
// specified.
//
// Arguments: LPCTSTR pszSectionName - full name of the server section to read
// (Server&Fred or whatever)
// CDunSetting* pDunSetting - Dun Settings data structure to store
// the read in values to
// LPCTSTR pszCmsFile - Cms file to read the settings from
// BOOL bTunnelDunSetting - whether this is a tunnel dun setting or not
//
// Returns: BOOL - TRUE if the settings were read in correctly
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
BOOL ReadDunServerSettings(LPCTSTR pszSectionName, CDunSetting* pDunSetting, LPCTSTR pszCmsFile, BOOL bTunnelDunSetting)
{
if ((NULL == pszSectionName) || (NULL == pDunSetting) || (NULL == pszCmsFile) ||
(TEXT('\0') == pszSectionName[0]) || (TEXT('\0') == pszCmsFile[0]))
{
CMASSERTMSG(FALSE, TEXT("ReadDunServerSettings -- invalid parameter"));
return FALSE;
}
GetBoolSettings ArrayOfServerSettings[] = {
{c_pszCmEntryDunServerNetworkLogon, &(pDunSetting->bNetworkLogon), bTunnelDunSetting},
{c_pszCmEntryDunServerSwCompress, &(pDunSetting->bPppSoftwareCompression), 1},
{c_pszCmEntryDunServerDisableLcp, &(pDunSetting->bDisableLCP), 0},
{c_pszCmEntryDunServerPwEncrypt, &(pDunSetting->bPWEncrypt), 0},
{c_pszCmEntryDunServerPwEncryptMs, &(pDunSetting->bPWEncrypt_MS), 0},
{c_pszCmEntryDunServerSecureLocalFiles, &(pDunSetting->bSecureLocalFiles), 0},
{c_pszCmEntryDunServerRequirePap, &(pDunSetting->bAllowPap), 0},
{c_pszCmEntryDunServerRequireSpap, &(pDunSetting->bAllowSpap), 0},
{c_pszCmEntryDunServerRequireEap, &(pDunSetting->bAllowEap), 0},
{c_pszCmEntryDunServerRequireChap, &(pDunSetting->bAllowChap), 0},
{c_pszCmEntryDunServerRequireMsChap, &(pDunSetting->bAllowMsChap), 0},
{c_pszCmEntryDunServerRequireMsChap2, &(pDunSetting->bAllowMsChap2), 0},
{c_pszCmEntryDunServerRequireW95MsChap, &(pDunSetting->bAllowW95MsChap), 0},
{c_pszCmEntryDunServerDataEncrypt, &(pDunSetting->bDataEncrypt), 0},
};
const int c_iNumDunServerBools = sizeof(ArrayOfServerSettings)/sizeof(ArrayOfServerSettings[0]);
for (int i = 0; i < c_iNumDunServerBools; i++)
{
*(ArrayOfServerSettings[i].pbValue) = GetPrivateProfileInt(pszSectionName, ArrayOfServerSettings[i].pszKeyName,
ArrayOfServerSettings[i].bDefault, pszCmsFile);
}
//
// Now get the EAP settings if necessary
//
pDunSetting->dwCustomAuthKey = GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunServerCustomAuthKey, 0, pszCmsFile);
if (pDunSetting->dwCustomAuthKey)
{
if (!ReadDunSettingsEapData(pszSectionName, &(pDunSetting->pCustomAuthData), &(pDunSetting->dwCustomAuthDataSize), pDunSetting->dwCustomAuthKey, pszCmsFile))
{
CMASSERTMSG(FALSE, TEXT("ReadDunServerSettings -- Failed to read in EAP Data."));
pDunSetting->dwCustomAuthDataSize = 0;
CmFree(pDunSetting->pCustomAuthData);
pDunSetting->pCustomAuthData = NULL;
}
}
//
// Now get the Encryption type
//
pDunSetting->dwEncryptionType = (DWORD)GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunServerEncryptionType,
(bTunnelDunSetting ? ET_Require : ET_Optional), pszCmsFile);
//
// Figure out what type of security model we are using
//
if (GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunServerEnforceCustomSecurity, 0, pszCmsFile))
{
pDunSetting->iHowToHandleSecuritySettings = FORCE_WIN2K_AND_ABOVE;
}
else
{
int iWin2kSecSettings = pDunSetting->bAllowPap | pDunSetting->bAllowSpap | pDunSetting->bAllowEap |
pDunSetting->bAllowChap | pDunSetting->bAllowMsChap | pDunSetting->bAllowMsChap2 |
pDunSetting->bAllowW95MsChap;
if (iWin2kSecSettings)
{
pDunSetting->iHowToHandleSecuritySettings = SEPARATE_FOR_LEGACY_AND_WIN2K;
}
else
{
pDunSetting->iHowToHandleSecuritySettings = SAME_ON_ALL_PLATFORMS;
//
// In case the user chooses the advanced tab without configuring settings, lets
// set some reasonable defaults for them. If they have already configured their
// Win2k settings we don't want to mess with them. Also note that if the user
// doesn't change the iHowToHandleSecuritySettings value, we won't write out
// the advanced security settings anyway.
//
pDunSetting->bAllowChap = !bTunnelDunSetting;
pDunSetting->bAllowMsChap = 1;
pDunSetting->bAllowMsChap2 = 1;
}
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: ReadDunNetworkingSettings
//
// Synopsis: Reads in all of the settings from the DUN Networking section
// specified.
//
// Arguments: LPCTSTR pszSectionName - full name of the networking section to read
// (Networking&Fred or whatever)
// CDunSetting* pDunSetting - Dun Settings data structure to store
// the read in values to
// LPCTSTR pszCmsFile - Cms file to read the settings from
// BOOL bTunnel - is this a tunnel DUN setting or not
//
// Returns: BOOL - TRUE if the settings were read in correctly
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
BOOL ReadDunNetworkingSettings(LPCTSTR pszSectionName, CDunSetting* pDunSetting, LPCTSTR pszCmsFile, BOOL bTunnel)
{
if ((NULL == pszSectionName) || (NULL == pDunSetting) || (NULL == pszCmsFile) ||
(TEXT('\0') == pszSectionName[0]) || (TEXT('\0') == pszCmsFile[0]))
{
CMASSERTMSG(FALSE, TEXT("ReadDunNetworkingSettings -- invalid parameter"));
return FALSE;
}
pDunSetting->dwVpnStrategy = (DWORD)GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunNetworkingVpnStrategy,
(bTunnel ? VS_PptpFirst : 0), pszCmsFile);
//
// If the profile had automatic, then set it to VS_PptpFirst instead.
//
if (bTunnel && ((VS_PptpOnly > pDunSetting->dwVpnStrategy) || (VS_L2tpFirst < pDunSetting->dwVpnStrategy)))
{
pDunSetting->dwVpnStrategy = VS_PptpFirst;
}
//
// Get the value for UseDownLevelL2TP
//
pDunSetting->bUseDownLevelL2TP = (BOOL)GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunNetworkingUseDownLevelL2TP,
FALSE, pszCmsFile);
pDunSetting->bUsePskOnWin2kPlus = (BOOL)GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunNetworkingUsePreSharedKey,
FALSE, pszCmsFile);
pDunSetting->bUsePskDownLevel = (BOOL)GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunNetworkingUsePskDownLevel,
FALSE, pszCmsFile);
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: ConvertIpStringToDword
//
// Synopsis: This function takes the given string containing an IP address and
// converts it to a packed DWORD. The first octet of the IP address
// going in the most significant byte of the DWORD, the next octet in
// the second most significant byte of the DWORD, etc. The packed
// DWORD format is used by the IP address common controls and is a much
// easier format to store the data in than a string.
//
// Arguments: LPTSTR pszIpAddress - string containing the ip address, each octet
// seperated by a period.
//
// Returns: DWORD - the ip address specified by the inputted string in
// packed byte format (first octet in the most significant)
// Note that zero is returned if there is a problem with the
// IP address format (one of the numbers is out of bounds or
// there are too many or too few octets).
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
DWORD ConvertIpStringToDword(LPTSTR pszIpAddress)
{
DWORD dwIpAddress = 0;
if (pszIpAddress && pszIpAddress[0])
{
CmStrTrim(pszIpAddress);
LPTSTR pszCurrent = pszIpAddress;
DWORD dwOctetCounter = 0;
DWORD dwCurrentOctetValue = 0;
const int c_iCharBase = TEXT('0');
BOOL bExitLoop = FALSE;
while (pszCurrent && !bExitLoop)
{
switch(*pszCurrent)
{
case TEXT('.'):
if (3 > dwOctetCounter)
{
dwIpAddress = (dwIpAddress << 8) + dwCurrentOctetValue;
dwOctetCounter++;
dwCurrentOctetValue = 0;
}
else
{
CMASSERTMSG(FALSE, TEXT("ConvertIpStringToDword -- Too many octets"));
return 0;
}
break;
case TEXT('\0'):
if (3 == dwOctetCounter)
{
dwIpAddress = (dwIpAddress << 8) + dwCurrentOctetValue;
bExitLoop = TRUE;
}
else
{
CMASSERTMSG(FALSE, TEXT("ConvertIpStringToDword -- Incorrect number of octets"));
return 0;
}
break;
default:
dwCurrentOctetValue = dwCurrentOctetValue*10 + (int(*pszCurrent) - c_iCharBase);
if (255 < dwCurrentOctetValue)
{
CMASSERTMSG(FALSE, TEXT("ConvertIpStringToDword -- Octet value out of range"));
return 0;
}
break;
}
pszCurrent = CharNext(pszCurrent);
}
}
return dwIpAddress;
}
//+----------------------------------------------------------------------------
//
// Function: ConvertIpDwordToString
//
// Synopsis: This function takes the given Packed DWORD and returns an IP
// address string for it, making sure to print the octets so that
// the most significant bits are printed in the string first.
//
// Arguments: DWORD dwIpAddress - packed DWORD containing the Ip address to convert
// LPTSTR pszIpAddress - string to write the IP address too
//
// Returns: int - the number of chars written to the string buffer. Zero signifies
// failure.
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
int ConvertIpDwordToString(DWORD dwIpAddress, LPTSTR pszIpAddress)
{
int iReturn = 0;
if (pszIpAddress)
{
iReturn = wsprintf(pszIpAddress, TEXT("%d.%d.%d.%d"), FIRST_IPADDRESS(dwIpAddress), SECOND_IPADDRESS(dwIpAddress),
THIRD_IPADDRESS(dwIpAddress), FOURTH_IPADDRESS(dwIpAddress));
}
else
{
CMASSERTMSG(FALSE, TEXT("ConvertIpDwordToString -- Null pointer passed for pszIpAddress"));
}
return iReturn;
}
//+----------------------------------------------------------------------------
//
// Function: ReadDunTcpIpSettings
//
// Synopsis: This function reads the TCP/IP DUN settings from the specified
// section and stores them in the given pDunSetting structure.
//
// Arguments: LPCTSTR pszSectionName - complete section name to read the TCP/IP
// settings from, ie. Networking&Fred
// CDunSetting* pDunSetting - pointer to a DUN setting structure to hold
// the read in data
// LPCTSTR pszCmsFile - cms file to read the settings from
//
// Returns: BOOL - TRUE on success
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
BOOL ReadDunTcpIpSettings(LPCTSTR pszSectionName, CDunSetting* pDunSetting, LPCTSTR pszCmsFile)
{
if ((NULL == pszSectionName) || (NULL == pDunSetting) || (NULL == pszCmsFile) ||
(TEXT('\0') == pszSectionName[0]) || (TEXT('\0') == pszCmsFile[0]))
{
CMASSERTMSG(FALSE, TEXT("ReadDunTcpIpSettings -- invalid parameter"));
return FALSE;
}
TCHAR szTemp[MAX_PATH];
//
// Are we using Admin specified DNS and WINS settings or is the server going to assign them
//
if (GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunTcpIpSpecifyServerAddress, 0, pszCmsFile))
{
//
// Get the DNS and WINS configurations that were specified
//
GetPrivateProfileString(pszSectionName, c_pszCmEntryDunTcpIpDnsAddress, TEXT(""), szTemp, CELEMS(szTemp), pszCmsFile);
pDunSetting->dwPrimaryDns = ConvertIpStringToDword (szTemp);
GetPrivateProfileString(pszSectionName, c_pszCmEntryDunTcpIpDnsAltAddress, TEXT(""), szTemp, CELEMS(szTemp), pszCmsFile);
pDunSetting->dwSecondaryDns = ConvertIpStringToDword (szTemp);
GetPrivateProfileString(pszSectionName, c_pszCmEntryDunTcpIpWinsAddress, TEXT(""), szTemp, CELEMS(szTemp), pszCmsFile);
pDunSetting->dwPrimaryWins = ConvertIpStringToDword (szTemp);
GetPrivateProfileString(pszSectionName, c_pszCmEntryDunTcpIpWinsAltAddress, TEXT(""), szTemp, CELEMS(szTemp), pszCmsFile);
pDunSetting->dwSecondaryWins = ConvertIpStringToDword (szTemp);
}
else
{
pDunSetting->dwPrimaryDns = 0;
pDunSetting->dwSecondaryDns = 0;
pDunSetting->dwPrimaryWins = 0;
pDunSetting->dwSecondaryWins = 0;
}
//
// Now Read in IP Header Compress and whether to use the Remote Gateway or not
//
pDunSetting->bIpHeaderCompression = GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunTcpIpIpHeaderCompress, 1, pszCmsFile);
pDunSetting->bGatewayOnRemote = GetPrivateProfileInt(pszSectionName, c_pszCmEntryDunTcpIpGatewayOnRemote, 1, pszCmsFile);
return 0;
}
//+----------------------------------------------------------------------------
//
// Function: ReadDunScriptingSettings
//
// Synopsis: This function reads in the script name from the passed in scripting
// section name and stores it in the passed in DUN setting struct.
//
// Arguments: LPCTSTR pszSectionName - complete section name to read the scripting
// settings from, ie. Scripting&Fred
// CDunSetting* pDunSetting - pointer to a DUN setting structure to hold
// the read in data
// LPCTSTR pszCmsFile - cms file to read the settings from
//
// Returns: BOOL - TRUE on success
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
BOOL ReadDunScriptingSettings(LPCTSTR pszSectionName, CDunSetting* pDunSetting, LPCTSTR pszOsDir, LPCTSTR pszCmsFile)
{
if ((NULL == pszSectionName) || (NULL == pDunSetting) || (NULL == pszCmsFile) || (NULL == pszOsDir) ||
(TEXT('\0') == pszSectionName[0]) || (TEXT('\0') == pszCmsFile[0]) || (TEXT('\0') == pszOsDir[0]))
{
CMASSERTMSG(FALSE, TEXT("ReadDunScriptingSettings -- invalid parameter"));
return FALSE;
}
TCHAR szTemp[MAX_PATH+1] = TEXT("");
if (GetPrivateProfileString(pszSectionName, c_pszCmEntryDunScriptingName, TEXT(""),
szTemp, CELEMS(szTemp), pszCmsFile))
{
MYVERIFY(CELEMS(pDunSetting->szScript) > (UINT)wsprintf(pDunSetting->szScript, TEXT("%s%s"), pszOsDir, szTemp));
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: AddDunNameToListIfDoesNotExist
//
// Synopsis: This function walks through the list of existing DUN settings
// to see if it can find a setting with the name pszDunName. If it
// finds the entry, then fine it returns TRUE. If it cannot find the
// entry then it creates an otherwise blank entry and adds it to the list.
//
// Arguments: LPCTSTR pszDunName - name of the item to add to the list if
// it doesn't already exist
// ListBxList **pHeadDns - head of the list of DUN entries
// ListBxList** pTailDns - tail of the list of DUN entries
// BOOL bTunnelDunName - whether this is a tunnel DUN name or not
//
// Returns: BOOL - TRUE if the item was added or if it already existed in the list
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
BOOL AddDunNameToListIfDoesNotExist(LPCTSTR pszDunName, ListBxList **pHeadDns, ListBxList** pTailDns, BOOL bTunnelDunName)
{
if ((NULL == pszDunName) || (NULL == pHeadDns) || (NULL == pTailDns) || (TEXT('\0') == pszDunName[0]))
{
CMASSERTMSG(FALSE, TEXT("AddDunNameToListIfDoesNotExist -- Invalid Parameter"));
return FALSE;
}
ListBxList* pCurrent = *pHeadDns;
BOOL bReturn = TRUE;
while (pCurrent)
{
if (0 == lstrcmpi(pszDunName, pCurrent->szName))
{
//
// We already have this item, nothing to do
//
goto exit;
}
pCurrent = pCurrent->next;
}
//
// If we are here then either we didn't find the item or the list
// is empty. Either way, add the item.
//
pCurrent = (ListBxList*)CmMalloc(sizeof(ListBxList));
if (pCurrent)
{
pCurrent->ListBxData = new CDunSetting(bTunnelDunName);
if (NULL == pCurrent->ListBxData)
{
CmFree(pCurrent);
CMASSERTMSG(FALSE, TEXT("AddDunNameToListIfDoesNotExist -- Failed to allocate a new CDunSetting"));
return FALSE;
}
}
else
{
CMASSERTMSG(FALSE, TEXT("ReadDunServerSettings -- Failed to allocate a new ListBxList struct"));
return FALSE;
}
//
// Now that we have allocated a pCurrent, we need to add it to the list
//
if (NULL == *pHeadDns)
{
*pHeadDns = pCurrent;
}
else
{
(*pTailDns)->next = pCurrent;
}
*pTailDns = pCurrent;
//
// Finally copy the name over
//
lstrcpy(pCurrent->szName, pszDunName);
exit:
return bReturn;
}
//+----------------------------------------------------------------------------
//
// Function: GetVpnEntryNamesFromFile
//
// Synopsis: This function parses through the tunnel server address entries within
// the given VPN file. For each entry that contains a VPN setting,
// if calls AddDunNameToListIfDoesNotExist.
//
// Arguments: LPCTSTR pszPhoneBook - VPN file to search for VPN entry names
// ListBxList **pHeadDns - head of the VPN entry list
// ListBxList** pTailDns - tail of the VPN entry list
//
// Returns: BOOL - TRUE if the phonebook was successfully parsed.
//
// History: quintinb Created 10/28/00
//
//+----------------------------------------------------------------------------
BOOL GetVpnEntryNamesFromFile(LPCTSTR pszVpnFile, ListBxList **pHeadDns, ListBxList** pTailDns)
{
if ((NULL == pszVpnFile) || (NULL == pHeadDns) || (NULL == pTailDns))
{
CMASSERTMSG(FALSE, TEXT("GetVpnEntryNamesFromFile -- invalid params passed."));
return FALSE;
}
//
// Note that the vpn file string passed in may be empty. That is okay because the profile
// may be a tunneling profile using only one tunnel address.
//
if ((TEXT('\0') != pszVpnFile[0]))
{
LPTSTR pszVpnServersSection = GetPrivateProfileSectionWithAlloc(c_pszCmSectionVpnServers, pszVpnFile);
if (pszVpnServersSection)
{
LPTSTR pszCurrentLine = pszVpnServersSection;
LPTSTR pszVpnSetting = NULL;
while (TEXT('\0') != (*pszCurrentLine))
{
//
// First look for the equal sign
//
pszVpnSetting = CmStrchr(pszCurrentLine, TEXT('='));
if (pszVpnSetting)
{
//
// Now look for the last comma
//
pszVpnSetting = CmStrrchr(pszVpnSetting, TEXT(','));
if (pszVpnSetting)
{
pszVpnSetting = CharNext(pszVpnSetting);
MYVERIFY(AddDunNameToListIfDoesNotExist(pszVpnSetting, pHeadDns, pTailDns, TRUE)); // TRUE == bTunnelDunName
}
}
//
// Find the next string by going to the end of the string
// and then going one more char. Note that we cannot use
// CharNext here but must use just ++.
//
pszCurrentLine = CmEndOfStr(pszCurrentLine);
pszCurrentLine++;
}
}
else
{
CMASSERTMSG(FALSE, TEXT("GetVpnEntryNamesFromFile -- GetPrivateProfileSectionWithAlloc return NULL."));
return FALSE;
}
CmFree(pszVpnServersSection);
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: VerifyVpnFile
//
// Synopsis: This function examines the VPN servers section of a VPN file
// to ensure that at least one line of a valid format is found. While
// this doesn't guarantee that the entry is valid (it could be a bogus
// server name), it does at least mean the Admin didn't give the user a
// junk file. This is important because the user cannot enter their own
// tunnel server destination.
//
// Arguments: LPCTSTR pszPhoneBook - VPN file to search for VPN entry names
//
// Returns: BOOL - TRUE if the VPN file contains at least one tunnel server
// entry in a valid format
//
// History: quintinb Created 10/28/00
//
//+----------------------------------------------------------------------------
BOOL VerifyVpnFile(LPCTSTR pszVpnFile)
{
if (NULL == pszVpnFile)
{
CMASSERTMSG(FALSE, TEXT("VerifyVpnFile -- invalid params passed."));
return FALSE;
}
BOOL bReturn = FALSE;
//
// Note that the vpn file string passed in may be empty. That is okay because the profile
// may be a tunneling profile using only one tunnel address.
//
if ((TEXT('\0') != pszVpnFile[0]))
{
LPTSTR pszVpnServersSection = GetPrivateProfileSectionWithAlloc(c_pszCmSectionVpnServers, pszVpnFile);
if (pszVpnServersSection)
{
LPTSTR pszCurrentLine = pszVpnServersSection;
LPTSTR pszEqualSign = NULL;
while ((TEXT('\0') != (*pszCurrentLine)) && !bReturn)
{
//
// To be considered a "valid" line, all we need is to have
// an equal sign (=) surrounded by text. Not that stringent of a test
// but better than nothing.
//
pszEqualSign = CmStrchr(pszCurrentLine, TEXT('='));
if (pszEqualSign && (pszEqualSign != pszCurrentLine)) // line cannot start with an equal sign to count
{
pszCurrentLine = CharNext(pszEqualSign);
CmStrTrim(pszCurrentLine);
if (*pszCurrentLine)
{
bReturn = TRUE;
}
}
//
// Find the next string by going to the end of the string
// and then going one more char. Note that we cannot use
// CharNext here but must use just ++.
//
pszCurrentLine = CmEndOfStr(pszCurrentLine);
pszCurrentLine++;
}
CmFree(pszVpnServersSection);
}
}
return bReturn;
}
//+----------------------------------------------------------------------------
//
// Function: GetDunEntryNamesFromPbk
//
// Synopsis: This function memory maps the given phonebook into memory and
// then walks through it as one big string. The function is searching
// the phonebook for DUN entry names. If it finds a DUN entry name then
// it uses AddDunNameToListIfDoesNotExist to add the entry name if
// it doesn't already exist.
//
// Arguments: LPCTSTR pszPhoneBook - phonebook to search for DUN entry names
// ListBxList **pHeadDns - head of the DUN entry list
// ListBxList** pTailDns - tail of the DUN entry list
//
// Returns: BOOL - TRUE if the phonebook was successfully parsed.
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
BOOL GetDunEntryNamesFromPbk(LPCTSTR pszPhoneBook, ListBxList **pHeadDns, ListBxList** pTailDns)
{
if ((NULL == pszPhoneBook) || (NULL == pHeadDns) || (NULL == pTailDns))
{
CMASSERTMSG(FALSE, TEXT("GetDunEntryNamesFromPbk -- Invalid Parameter"));
return FALSE;
}
BOOL bReturn = TRUE;
if ((TEXT('\0') != pszPhoneBook[0]))
{
HANDLE hPhoneBookFile = CreateFile(pszPhoneBook, GENERIC_READ, FILE_SHARE_READ, NULL,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if (INVALID_HANDLE_VALUE != hPhoneBookFile)
{
//
// Get the size of the file
//
DWORD dwFileSize = GetFileSize(hPhoneBookFile, NULL);
if (-1 != dwFileSize)
{
//
// Create a file mapping
//
HANDLE hFileMapping = CreateFileMapping(hPhoneBookFile, NULL, PAGE_READONLY, 0, 0, NULL);
if (NULL != hFileMapping)
{
CHAR* pszPhoneBookContents = (CHAR*)MapViewOfFileEx(hFileMapping, FILE_MAP_READ, 0, 0, 0, NULL);
CHAR* pszCurrent = pszPhoneBookContents;
LPSTR pszLastComma = NULL;
//
// We want to walk through the file character by character. Whenever we encounter
// a '\n', we know that is the end of a line. If we hit EOF then we are done with the file.
// We are looking for all of the DUN entry names in the phonebook file.
//
while (pszCurrent && ((dwFileSize + pszPhoneBookContents) > pszCurrent))
{
CHAR szTemp[MAX_PATH+1];
int iNumChars;
switch (*pszCurrent)
{
case ',':
pszLastComma = pszCurrent;
break;
case '\r':
//
// End of a line, remember we have a \r\n <CRLF> to end a line in a file.
//
if (pszLastComma)
{
iNumChars = (int)(pszCurrent - pszLastComma);
if (iNumChars - 1)
{
lstrcpynA(szTemp, CharNextA(pszLastComma), iNumChars);
LPTSTR pszUnicodeDunName = SzToWzWithAlloc(szTemp);
MYDBGASSERT(pszUnicodeDunName);
if (pszUnicodeDunName)
{
MYVERIFY(AddDunNameToListIfDoesNotExist(pszUnicodeDunName, pHeadDns, pTailDns, FALSE)); // FALSE == bTunnelDunName
CmFree(pszUnicodeDunName);
}
}
//
// Reset the last comma
//
pszLastComma = NULL;
}
break;
case '\0':
case EOF:
//
// We shouldn't hit an EOF or a zero byte in a memory mapped text file.
//
bReturn = FALSE;
CMASSERTMSG(FALSE, TEXT("GetDunEntryNamesFromPbk -- phonebook file format incorrect!"));
break;
}
//
// Advance to the next line assuming we still have some of the file
// to parse
//
if (pszCurrent && ((EOF == *pszCurrent) || ('\0' == *pszCurrent)))
{
//
// Then we have an invalid file and it is time to exit...
//
pszCurrent = NULL;
}
else if (pszCurrent)
{
pszCurrent = CharNextA(pszCurrent);
}
}
MYVERIFY(UnmapViewOfFile(pszPhoneBookContents));
CloseHandle(hFileMapping);
}
}
CloseHandle(hPhoneBookFile);
}
}
return bReturn;
}
//+----------------------------------------------------------------------------
//
// Function: CDunSetting::CDunSetting
//
// Synopsis: Constructor for the CDunSetting data structure. Note that all
// default values should be changed here and not imposed anywhere
// else. All the DUN setting UI is setup to read from a DUN setting
// structure, either a newly constructed one (thus setting up the defaults)
// or one read in from the cms.
//
// Arguments: BOOL bTunnel - tells whether this is a Tunnel DUN setting or not
// note that this value defaults to FALSE.
//
// Returns: Nothing
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
CDunSetting::CDunSetting(BOOL bTunnel)
{
//
// Note that bTunnelDunSetting has a default value of FALSE.
// Init the class params.
//
bNetworkLogon = bTunnel ? 1 : 0;
bPppSoftwareCompression = 1;
bDisableLCP = 0;
bPWEncrypt = bTunnel ? 0 : 1; // if we are not tunneling, default to secure password
bPWEncrypt_MS = bTunnel ? 1 : 0; // if we are tunneling, default to MS secure password
szScript[0] = TEXT('\0');
dwVpnStrategy = bTunnel ? VS_PptpFirst : 0;
bTunnelDunSetting = bTunnel;
bUseDownLevelL2TP = 0;
//
// TCP/IP Settings
//
dwPrimaryDns = 0;
dwSecondaryDns = 0;
dwPrimaryWins = 0;
dwSecondaryWins = 0;
bIpHeaderCompression = 1;
bGatewayOnRemote = 1;
//
// Security Settings
//
dwEncryptionType = bTunnel ? ET_Require : ET_Optional;
bDataEncrypt = bTunnel ? 1 : 0; // if we are tunneling, default to data encryption
bAllowPap = 0;
bAllowSpap = 0;
bAllowEap = 0;
bAllowChap = bTunnel ? 0 : 1;
bAllowMsChap = 1;
bAllowMsChap2 = 1;
bAllowW95MsChap = 0;
bSecureLocalFiles = 0;
//
// Due to RASEO_RequireMsEncryptPw & MSCAHPv2 bug in RAS API on Win2K & XP
// we want a default profile to correctly work on Win2k and above. Thus
// CMAK needs to default to lagacy and Win2k settings. That way the correct Win2K+ RASEO_ flags
// are written out.
//
iHowToHandleSecuritySettings = SEPARATE_FOR_LEGACY_AND_WIN2K;
dwCustomAuthKey = 0;
pCustomAuthData = NULL;
dwCustomAuthDataSize = 0;
bUsePskOnWin2kPlus = 0;
bUsePskDownLevel = 0;
}
//+----------------------------------------------------------------------------
//
// Function: CDunSetting::~CDunSetting
//
// Synopsis: Destructor for the CDunSetting data structure. Frees the EAP
// blob if one exists
//
// Arguments: None
//
// Returns: Nothing
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
CDunSetting::~CDunSetting()
{
CmFree(pCustomAuthData);
}
//+----------------------------------------------------------------------------
//
// Function: ReadNetworkSettings
//
// Synopsis: Constructor for the CDunSetting data structure. Note that all
// default values should be changed here and not imposed anywhere
// else. All the DUN setting UI is setup to read from a DUN setting
// structure, either a newly constructed one (thus setting up the defaults)
// or one read in from the cms.
//
// Arguments: LPCTSTR pszCmsFile - Cms file to read the network settings from
// LPCTSTR pszLongServiceName - Long service name of the profile
// LPCTSTR pszPhoneBook - phonebook of the current service profile,
// if the profile doesn't have a phonebook
// then "" should be passed
// ListBxList **pHeadDns - pointer to the head of the DUN settings list
// ListBxList** pTailDns - pointer to the tail of the DUN settings list
// LPCTSTR pszOsDir - full path of the profiles directory
//
// Returns: BOOL - TRUE if successful
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
BOOL ReadNetworkSettings(LPCTSTR pszCmsFile, LPCTSTR pszLongServiceName, LPCTSTR pszPhoneBook,
ListBxList **pHeadDns, ListBxList** pTailDns, LPCTSTR pszOsDir, BOOL bLookingForVpnEntries)
{
//
// Check inputs, note that the phonebook could be ""
//
if ((NULL == pszCmsFile) || (NULL == pszLongServiceName) || (NULL == pszPhoneBook) || (NULL == pszOsDir) || (NULL == pHeadDns) ||
(NULL == pTailDns) || (TEXT('\0') == pszCmsFile[0]) || (TEXT('\0') == pszLongServiceName[0]) || (TEXT('\0') == pszOsDir[0]) ||
((NULL == *pHeadDns) ^ (NULL == *pTailDns)))
{
CMASSERTMSG(FALSE, TEXT("ReadNetworkSettings -- invalid parameter"));
return FALSE;
}
BOOL bReturn = TRUE;
LPTSTR pszCurrentSectionName = NULL;
TCHAR szDefaultDunName[MAX_PATH+1] = TEXT("");
TCHAR szTunnelDunName[MAX_PATH+1] = TEXT("");
//
// First we want to call GetPrivateProfileString with a NULL AppName and a NULL KeyName. This will
// Return all of the Section Names in the file in a buffer. We can then go through the buffer and
// get the section information that interests us.
//
LPTSTR pszSectionNames = GetPrivateProfileStringWithAlloc(NULL, NULL, TEXT(""), pszCmsFile);
if ((NULL == pszSectionNames) || (TEXT('\0') == pszSectionNames[0]))
{
CMTRACE(TEXT("ReadNetworkSettings -- GetPrivateProfileStringWithAlloc failed"));
bReturn = FALSE;
goto exit;
}
//
// At this point we have a list of section names, they are all NULL terminated with the last one double
// NULL terminated. We need to walk through the list and see if any of them start with "[TCP/IP&" if
// so then we have a DUN section and we want to read it in.
//
LPTSTR pszAmpersand;
LPTSTR pszDunName;
TCHAR szTemp[MAX_PATH+1];
BOOL bTunnelDunSetting;
pszCurrentSectionName = pszSectionNames;
//
// Get the name of the Tunnel Dun setting
//
MYVERIFY(0 != GetTunnelDunSettingName(pszCmsFile, pszLongServiceName, szTunnelDunName, CELEMS(szTunnelDunName)));
//
// Get the name of the default Dun setting
//
MYVERIFY(0 != GetDefaultDunSettingName(pszCmsFile, pszLongServiceName, szDefaultDunName, CELEMS(szDefaultDunName)));
while (TEXT('\0') != (*pszCurrentSectionName))
{
pszAmpersand = CmStrchr(pszCurrentSectionName, TEXT('&'));
if (pszAmpersand)
{
//
// Then we have a DUN or VPN section name.
//
pszDunName = CharNext(pszAmpersand);
//
// Next we need to see if the entry that we have is of the type we
// are looking for ... a VPN entry if bLookingForVpnEntries is TRUE
// or a DUN entry if bLookingForVpnEntries is FALSE. We can tell the
// DUN and VPN entries apart by the existence of a Networking&<name>
// section or because it is the VPN default entryname.
//
wsprintf(szTemp, TEXT("%s&%s"), c_pszCmSectionDunNetworking, pszDunName);
BOOL bIsVpnEntry = GetPrivateProfileInt(szTemp, c_pszCmEntryDunNetworkingVpnEntry, 0, pszCmsFile);
bTunnelDunSetting = (bIsVpnEntry || (0 == lstrcmpi(szTunnelDunName, pszDunName)));
//
// If we have a VPN entry and are looking for VPN entries or we have a DUN entry and are looking for
// DUN entries, then go ahead and process it.
//
if ((bTunnelDunSetting && bLookingForVpnEntries) || (!bTunnelDunSetting && !bLookingForVpnEntries))
{
ListBxList * pCurrent = *pHeadDns;
while (pCurrent)
{
if(0 == lstrcmpi(pCurrent->szName, pszDunName))
{
//
// Then we already have a DUN setting of this name
//
break;
}
pCurrent = pCurrent->next;
}
//
// We didn't find the item we were looking for, lets create one.
//
if (NULL == pCurrent)
{
pCurrent = (ListBxList*)CmMalloc(sizeof(ListBxList));
if (pCurrent)
{
pCurrent->ListBxData = new CDunSetting(bTunnelDunSetting);
if (NULL == pCurrent->ListBxData)
{
CmFree(pCurrent);
CMASSERTMSG(FALSE, TEXT("ReadDunServerSettings -- Failed to allocate a new DunSettingData struct"));
bReturn = FALSE;
goto exit;
}
}
else
{
CMASSERTMSG(FALSE, TEXT("ReadDunServerSettings -- Failed to allocate a new ListBxList struct"));
bReturn = FALSE;
goto exit;
}
//
// Now that we have allocated a pCurrent, we need to add it to the list
//
if (NULL == *pHeadDns)
{
*pHeadDns = pCurrent;
}
else
{
(*pTailDns)->next = pCurrent;
}
*pTailDns = pCurrent;
//
// Finally copy the name over
//
lstrcpy(pCurrent->szName, pszDunName);
((CDunSetting*)(pCurrent->ListBxData))->bTunnelDunSetting = bTunnelDunSetting;
}
//
// Now lets figure out which section type we have
//
DWORD dwSize = (DWORD)(pszAmpersand - pszCurrentSectionName + 1);
lstrcpyn(szTemp, pszCurrentSectionName, dwSize);
if (0 == lstrcmpi(szTemp, c_pszCmSectionDunServer))
{
ReadDunServerSettings(pszCurrentSectionName, (CDunSetting*)pCurrent->ListBxData, pszCmsFile, bTunnelDunSetting);
}
else if (0 == lstrcmpi(szTemp, c_pszCmSectionDunNetworking))
{
ReadDunNetworkingSettings(pszCurrentSectionName, (CDunSetting*)pCurrent->ListBxData, pszCmsFile, bTunnelDunSetting);
}
else if (0 == lstrcmpi(szTemp, c_pszCmSectionDunTcpIp))
{
ReadDunTcpIpSettings(pszCurrentSectionName, (CDunSetting*)pCurrent->ListBxData, pszCmsFile);
}
else if (0 == lstrcmpi(szTemp, c_pszCmSectionDunScripting))
{
ReadDunScriptingSettings(pszCurrentSectionName, (CDunSetting*)pCurrent->ListBxData, pszOsDir, pszCmsFile);
}
}
}
//
// Find the next string by going to the end of the string
// and then going one more char. Note that we cannot use
// CharNext here but must use just ++.
//
pszCurrentSectionName = CmEndOfStr(pszCurrentSectionName);
pszCurrentSectionName++;
}
//
// Now we have processed all of the settings that the user has, how about
// the settings that they could have. Lets add the default setting, the
// default Tunnel setting, and all of the settings from the
// current phonebook if there is one. Note that everyone has a tunnel setting,
// but we won't show it in the listbox if the user isn't tunneling.
//
if (bLookingForVpnEntries)
{
MYVERIFY(GetVpnEntryNamesFromFile(pszPhoneBook, pHeadDns, pTailDns));
MYVERIFY(AddDunNameToListIfDoesNotExist(szTunnelDunName, pHeadDns, pTailDns, TRUE)); // TRUE == bTunnelDunName
}
else
{
MYVERIFY(GetDunEntryNamesFromPbk(pszPhoneBook, pHeadDns, pTailDns));
MYVERIFY(AddDunNameToListIfDoesNotExist(szDefaultDunName, pHeadDns, pTailDns, FALSE)); // FALSE == bTunnelDunName
}
exit:
CmFree(pszSectionNames);
return bReturn;
}
//+----------------------------------------------------------------------------
//
// Function: WriteOutNetworkingEntry
//
// Synopsis: This function writes out the given networking entry to the
// appropriate DUN sections in the given cms file.
//
// Arguments: LPCTSTR pszDunName - name of the DUN setting
// CDunSetting* pDunSetting - settings data to output
// LPCTSTR pszShortServiceName - short service name of the profile
// LPCTSTR pszCmsFile - Cms file to write the settings too
//
// Returns: Nothing
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
void WriteOutNetworkingEntry(LPCTSTR pszDunName, CDunSetting* pDunSetting, LPCTSTR pszShortServiceName, LPCTSTR pszCmsFile)
{
if ((NULL == pszDunName) || (NULL == pDunSetting) || (NULL == pszCmsFile) || (NULL == pszShortServiceName) ||
(TEXT('\0') == pszCmsFile[0]) || (TEXT('\0') == pszDunName[0]) || (TEXT('\0') == pszShortServiceName[0]))
{
CMASSERTMSG(FALSE, TEXT("WriteOutNetworkingEntry -- Invalid input parameter"));
return;
}
//
// Lets build our four section headers
//
TCHAR szServerSection[MAX_PATH+1];
TCHAR szNetworkingSection[MAX_PATH+1];
TCHAR szTcpIpSection[MAX_PATH+1];
TCHAR szScriptingSection[MAX_PATH+1];
TCHAR szTemp[MAX_PATH+1] = {0};
TCHAR szEncryptionType[2] = {0};
TCHAR szVpnStrategy[2] = {0};
TCHAR szCustomAuthKey[32] = {0};
MYVERIFY(CELEMS(szServerSection) > (UINT)wsprintf(szServerSection, TEXT("%s&%s"), c_pszCmSectionDunServer, pszDunName));
MYVERIFY(CELEMS(szNetworkingSection) > (UINT)wsprintf(szNetworkingSection, TEXT("%s&%s"), c_pszCmSectionDunNetworking, pszDunName));
MYVERIFY(CELEMS(szTcpIpSection) > (UINT)wsprintf(szTcpIpSection, TEXT("%s&%s"), c_pszCmSectionDunTcpIp, pszDunName));
MYVERIFY(CELEMS(szScriptingSection) > (UINT)wsprintf(szScriptingSection, TEXT("%s&%s"), c_pszCmSectionDunScripting, pszDunName));
//
// Now setup a list of all of the Booleans we need to set.
//
SetBoolSettings SetBoolSettingsStruct[] = {
{szServerSection, c_pszCmEntryDunServerNetworkLogon, pDunSetting->bNetworkLogon},
{szServerSection, c_pszCmEntryDunServerSwCompress, pDunSetting->bPppSoftwareCompression},
{szServerSection, c_pszCmEntryDunServerDisableLcp, pDunSetting->bDisableLCP},
{szServerSection, c_pszCmEntryDunServerNegotiateTcpIp, 1}, // always negotiate TCP/IP
{szServerSection, c_pszCmEntryDunServerSecureLocalFiles, pDunSetting->bSecureLocalFiles},
{szTcpIpSection, c_pszCmEntryDunTcpIpIpHeaderCompress, pDunSetting->bIpHeaderCompression},
{szTcpIpSection, c_pszCmEntryDunTcpIpGatewayOnRemote, pDunSetting->bGatewayOnRemote}
};
const int c_iNumBools = sizeof(SetBoolSettingsStruct)/sizeof(SetBoolSettingsStruct[0]);
//
// Write out the boolean values
//
for (int i = 0; i < c_iNumBools; i++)
{
MYVERIFY(0 != WritePrivateProfileString(SetBoolSettingsStruct[i].pszSectionName,
SetBoolSettingsStruct[i].pszKeyName,
((SetBoolSettingsStruct[i].bValue) ? c_pszOne : c_pszZero),
pszCmsFile));
}
//
// Write out the security settings. If the user choose to use the same settings everywhere, then we
// only want to write out the legacy security flags. If the user choose to have separate settings
// then we need to write out both sets of settings. Or if the user choose to force win2k and above,
// we want to write out only the newer settings and set the EnforceCustomSecurity flag to TRUE
//
LPTSTR pszCustomSecurity = NULL;
LPTSTR pszEnforceCustomSecurity = NULL;
LPTSTR pszAllowPap = NULL;
LPTSTR pszAllowSpap = NULL;
LPTSTR pszAllowChap = NULL;
LPTSTR pszAllowMsChap = NULL;
LPTSTR pszAllowW95MsChap = NULL;
LPTSTR pszAllowMsChap2 = NULL;
LPTSTR pszAllowEAP = NULL;
LPTSTR pszEncryptionType = NULL;
LPTSTR pszVpnStrategy = NULL;
LPTSTR pszUseDownLevelL2TP = NULL;
LPTSTR pszCustomAuthKey = NULL;
LPTSTR pszUsePresharedKey = NULL;
LPTSTR pszUsePskDownLevel = NULL;
LPTSTR pszPwEncrypt = NULL;
LPTSTR pszPwEncryptMs = NULL;
LPTSTR pszDataEncrypt = NULL;
//
// Set the legacy security settings if we aren't forcing Win2k+
//
if ((SAME_ON_ALL_PLATFORMS == pDunSetting->iHowToHandleSecuritySettings) ||
(SEPARATE_FOR_LEGACY_AND_WIN2K == pDunSetting->iHowToHandleSecuritySettings))
{
pszPwEncrypt = (LPTSTR)(pDunSetting->bPWEncrypt ? c_pszOne : c_pszZero);
pszPwEncryptMs = (LPTSTR)(pDunSetting->bPWEncrypt_MS ? c_pszOne : c_pszZero);
pszDataEncrypt = (LPTSTR)((pDunSetting->bPWEncrypt_MS & pDunSetting->bDataEncrypt) ? c_pszOne : c_pszZero);
}
//
// Set the Win2k specific settings if we aren't using the same settings everywhere
//
if ((FORCE_WIN2K_AND_ABOVE == pDunSetting->iHowToHandleSecuritySettings) ||
(SEPARATE_FOR_LEGACY_AND_WIN2K == pDunSetting->iHowToHandleSecuritySettings))
{
if (FORCE_WIN2K_AND_ABOVE == pDunSetting->iHowToHandleSecuritySettings)
{
pszEnforceCustomSecurity = (LPTSTR)c_pszOne;
}
else
{
pszEnforceCustomSecurity = (LPTSTR)c_pszZero;
}
pszCustomSecurity = (LPTSTR)c_pszOne;
if (pDunSetting->bAllowEap)
{
pszAllowEAP = (LPTSTR)c_pszOne;
wsprintf(szCustomAuthKey, TEXT("%d"), pDunSetting->dwCustomAuthKey);
pszCustomAuthKey = szCustomAuthKey;
}
else
{
pszAllowPap = (LPTSTR)(pDunSetting->bAllowPap ? c_pszOne : c_pszZero);
pszAllowSpap = (LPTSTR)(pDunSetting->bAllowSpap ? c_pszOne : c_pszZero);
pszAllowChap = (LPTSTR)(pDunSetting->bAllowChap ? c_pszOne : c_pszZero);
pszAllowMsChap = (LPTSTR)(pDunSetting->bAllowMsChap ? c_pszOne : c_pszZero);
pszAllowMsChap2 = (LPTSTR)(pDunSetting->bAllowMsChap2 ? c_pszOne : c_pszZero);
pszAllowW95MsChap = (LPTSTR)(pDunSetting->bAllowW95MsChap ? c_pszOne : c_pszZero);
}
wsprintf(szEncryptionType, TEXT("%d"), pDunSetting->dwEncryptionType);
pszEncryptionType = szEncryptionType;
}
//
// Now write out the Win2k security settings
//
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerEnforceCustomSecurity, pszEnforceCustomSecurity, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerCustomSecurity, pszCustomSecurity, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerRequireEap, pszAllowEAP, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerCustomAuthKey, pszCustomAuthKey, pszCmsFile);
if (pszAllowEAP)
{
MYVERIFY(SUCCEEDED(WriteDunSettingsEapData(szServerSection, pDunSetting, pszCmsFile)));
}
else
{
MYVERIFY(SUCCEEDED(EraseDunSettingsEapData(szServerSection, pszCmsFile)));
}
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerRequirePap, pszAllowPap, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerRequireSpap, pszAllowSpap, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerRequireChap, pszAllowChap, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerRequireMsChap, pszAllowMsChap, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerRequireMsChap2, pszAllowMsChap2, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerRequireW95MsChap, pszAllowW95MsChap, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerEncryptionType, pszEncryptionType, pszCmsFile);
//
// Write out the Networking section if this is a VPN entry, otherwise blank the section. Don't forget to
// mark the entry as a VPN entry.
//
if (pDunSetting->bTunnelDunSetting)
{
//
// Okay, first let's figure out what the VPN settings need to be.
//
if (FORCE_WIN2K_AND_ABOVE == pDunSetting->iHowToHandleSecuritySettings)
{
pszUseDownLevelL2TP = NULL;
pszUsePskDownLevel = NULL;
wsprintf(szVpnStrategy, TEXT("%d"), pDunSetting->dwVpnStrategy);
pszVpnStrategy = szVpnStrategy;
pszUsePresharedKey = (LPTSTR)(pDunSetting->bUsePskOnWin2kPlus ? c_pszOne : NULL); // only write UsePreSharedKey if it is 1
}
else if (SEPARATE_FOR_LEGACY_AND_WIN2K == pDunSetting->iHowToHandleSecuritySettings)
{
wsprintf(szVpnStrategy, TEXT("%d"), pDunSetting->dwVpnStrategy);
pszVpnStrategy = szVpnStrategy;
//
// Only write out the PSK keys and the Downlevel L2TP key if they are 1
//
pszUseDownLevelL2TP = (LPTSTR)(pDunSetting->bUseDownLevelL2TP ? c_pszOne : NULL);
pszUsePskDownLevel = (LPTSTR)(pDunSetting->bUsePskDownLevel ? c_pszOne : NULL);
pszUsePresharedKey = (LPTSTR)(pDunSetting->bUsePskOnWin2kPlus ? c_pszOne : NULL);
}
else
{
//
// Using common settings for both Win2k+ and downlevel. Note that we are
// basing VpnStrategy and UsePreSharedKey (for XP) off of the downlevel values.
//
if (pDunSetting->bUsePskDownLevel)
{
pszUsePresharedKey = (LPTSTR)c_pszOne;
pszUsePskDownLevel = (LPTSTR)c_pszOne;
}
else
{
pszUsePresharedKey = NULL;
pszUsePskDownLevel = NULL;
}
if (pDunSetting->bUseDownLevelL2TP)
{
pszUseDownLevelL2TP = (LPTSTR)c_pszOne;
wsprintf(szVpnStrategy, TEXT("%d"), VS_L2tpFirst);
pszVpnStrategy = szVpnStrategy;
}
else
{
pszUseDownLevelL2TP = NULL;
wsprintf(szVpnStrategy, TEXT("%d"), VS_PptpFirst);
pszVpnStrategy = szVpnStrategy;
}
}
//
// Okay, now write them out
//
WritePrivateProfileString(szNetworkingSection, c_pszCmEntryDunNetworkingVpnStrategy, pszVpnStrategy, pszCmsFile);
WritePrivateProfileString(szNetworkingSection, c_pszCmEntryDunNetworkingUseDownLevelL2TP, pszUseDownLevelL2TP, pszCmsFile);
WritePrivateProfileString(szNetworkingSection, c_pszCmEntryDunNetworkingUsePreSharedKey, pszUsePresharedKey, pszCmsFile);
WritePrivateProfileString(szNetworkingSection, c_pszCmEntryDunNetworkingUsePskDownLevel, pszUsePskDownLevel, pszCmsFile);
WritePrivateProfileString(szNetworkingSection, c_pszCmEntryDunNetworkingVpnEntry, c_pszOne, pszCmsFile);
}
else
{
WritePrivateProfileString(szNetworkingSection, NULL, NULL, pszCmsFile);
}
//
// Write the legacy security settings
//
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerPwEncrypt, pszPwEncrypt, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerPwEncryptMs, pszPwEncryptMs, pszCmsFile);
WritePrivateProfileString(szServerSection, c_pszCmEntryDunServerDataEncrypt, pszDataEncrypt, pszCmsFile);
//
// Now write out the script section if we have one
//
if (pDunSetting->szScript[0])
{
TCHAR szScriptFile[MAX_PATH+1];
GetFileName(pDunSetting->szScript, szTemp);
MYVERIFY(CELEMS(szScriptFile) > (UINT)wsprintf(szScriptFile, TEXT("%s\\%s"), pszShortServiceName, szTemp));
MYVERIFY(0 != WritePrivateProfileString(szScriptingSection, c_pszCmEntryDunScriptingName, szScriptFile, pszCmsFile));
}
else
{
MYVERIFY(0 != WritePrivateProfileString(szScriptingSection, c_pszCmEntryDunScriptingName, NULL, pszCmsFile));
}
//
// Did the admin specify Wins and Dns addresses or is the server going to set them
//
if ((pDunSetting->dwPrimaryDns) || (pDunSetting->dwSecondaryDns) || (pDunSetting->dwPrimaryWins) || (pDunSetting->dwSecondaryWins))
{
MYVERIFY(ConvertIpDwordToString(pDunSetting->dwPrimaryDns, szTemp));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpDnsAddress, szTemp, pszCmsFile));
MYVERIFY(ConvertIpDwordToString(pDunSetting->dwSecondaryDns, szTemp));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpDnsAltAddress, szTemp, pszCmsFile));
MYVERIFY(ConvertIpDwordToString(pDunSetting->dwPrimaryWins, szTemp));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpWinsAddress, szTemp, pszCmsFile));
MYVERIFY(ConvertIpDwordToString(pDunSetting->dwSecondaryWins, szTemp));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpWinsAltAddress, szTemp, pszCmsFile));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpSpecifyServerAddress, c_pszOne, pszCmsFile));
}
else
{
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpSpecifyServerAddress, c_pszZero, pszCmsFile));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpDnsAddress, NULL, pszCmsFile));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpDnsAltAddress, NULL, pszCmsFile));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpWinsAddress, NULL, pszCmsFile));
MYVERIFY(0 != WritePrivateProfileString(szTcpIpSection, c_pszCmEntryDunTcpIpWinsAltAddress, NULL, pszCmsFile));
}
}
//+----------------------------------------------------------------------------
//
// Function: EraseNetworkingSections
//
// Synopsis: This function erases all the networking sections for the given
// DUN name. Thus if you give it a DUN name of Fred, it will
// erase Server&Fred, Networking&Fred, etc.
//
// Arguments: LPCTSTR pszDunName - base dun name to erase all of the settings for
// LPCTSTR pszCmsFile - cms file to erase the setting from
//
// Returns: Nothing
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
void EraseNetworkingSections(LPCTSTR pszDunName, LPCTSTR pszCmsFile)
{
TCHAR szSection[MAX_PATH+1];
const int c_iNumDunSubSections = 4;
const TCHAR* const ArrayOfSubSections[c_iNumDunSubSections] =
{
c_pszCmSectionDunServer,
c_pszCmSectionDunNetworking,
c_pszCmSectionDunTcpIp,
c_pszCmSectionDunScripting
};
if (pszDunName)
{
for (int i = 0; i < c_iNumDunSubSections; i++)
{
MYVERIFY(CELEMS(szSection) > (UINT)wsprintf(szSection, TEXT("%s&%s"), ArrayOfSubSections[i], pszDunName));
MYVERIFY(0 != WritePrivateProfileString(szSection, NULL, NULL, pszCmsFile));
}
}
}
//+----------------------------------------------------------------------------
//
// Function: WriteNetworkingEntries
//
// Synopsis: This function walks through the list of networking entries and
// either adds the networking entry to the given CMS file or
// if the entry is a VPN entry and the user turned off VPN's then
// it erases the VPN sections.
//
// Arguments: LPCTSTR pszCmsFile - Cms File to write the networking entries too
// LPCTSTR pszLongServiceName - long service name of the profile
// LPCTSTR pszShortServiceName - short service name of the profile
// ListBxList *g_pHeadDns - pointer to the head of the Dun entries list
//
// Returns: Nothing
//
// History: quintinb Created 03/22/00
//
//+----------------------------------------------------------------------------
void WriteNetworkingEntries(LPCTSTR pszCmsFile, LPCTSTR pszLongServiceName, LPCTSTR pszShortServiceName, ListBxList *pHeadDns)
{
MYDBGASSERT(pszCmsFile);
MYDBGASSERT(pszShortServiceName);
MYDBGASSERT(pszLongServiceName);
if (pszCmsFile && pszShortServiceName && pszLongServiceName && pHeadDns)
{
ListBxList * pCurrent = pHeadDns;
TCHAR szTemp[MAX_PATH];
TCHAR szTunnelDunName[MAX_PATH] = TEXT("");
//
// Get the name of the Tunnel Dun setting
//
MYVERIFY(0 != GetTunnelDunSettingName(pszCmsFile, pszLongServiceName, szTunnelDunName, CELEMS(szTunnelDunName)));
while (pCurrent)
{
//
// If we don't have any data for the entry (it was a placeholder that the user choose not to fill in) or
// if the entry is the tunneling entry and we aren't actually Tunneling then erase the entry instead of actually
// writing it out.
//
if (NULL == pCurrent->ListBxData)
{
EraseNetworkingSections(pCurrent->szName, pszCmsFile);
}
else
{
WriteOutNetworkingEntry(pCurrent->szName, (CDunSetting*)pCurrent->ListBxData, pszShortServiceName, pszCmsFile);
}
pCurrent = pCurrent->next;
}
}
}
//+----------------------------------------------------------------------------
//
// Function: EnableDisableDataEncryptCheckbox
//
// Synopsis: This function enables or disables the data encrypt checkbox
// depending on whether the user has selected to allow MsChap or not.
// For data encryption to be negotiated, the authentication protocol
// must be MsChap.
//
// Arguments: HWND hDlg - window handle to the dialog
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void EnableDisableDataEncryptCheckbox(HWND hDlg)
{
BOOL bMsChapEnabled = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_MS_ENCRYPTED_AUTH));
HWND hControl = GetDlgItem(hDlg, IDC_CHECK1);
if (hControl)
{
EnableWindow (hControl, bMsChapEnabled);
}
}
//+----------------------------------------------------------------------------
//
// Function: EnableDisableUsePskCheckbox
//
// Synopsis: This function enables or disables the use a pre-shared key checkbox
// depending on whether the user has selected to allow L2TP or not.
//
// Arguments: HWND hDlg - window handle to the dialog
//
// Returns: Nothing
//
// History: quintinb Created 09/12/01
//
//+----------------------------------------------------------------------------
void EnableDisableUsePskCheckbox(HWND hDlg)
{
BOOL bL2TPEnabled = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_USE_L2TP));
HWND hControl = GetDlgItem(hDlg, IDC_CHECK2);
if (hControl)
{
EnableWindow (hControl, bL2TPEnabled);
}
}
//+----------------------------------------------------------------------------
//
// Function: ProcessSecurityPopup
//
// Synopsis: This function processes messages for the simple security dialog.
// This dialog only contains authorization protocols and encryption
// settings supported on all platforms.
//
// Arguments: HWND hDlg - window handle to the dialog
// UINT message - the current message to process
// WPARAM wParam - wParam see individual message type for details
// LPARAM lParam - lParam see individual message type for details
//
// Returns: INT_PTR - TRUE if the message was completely handled
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
INT_PTR APIENTRY ProcessSecurityPopup(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static DWORD_PTR HelpId = 0;
static CDunSetting* pDunSetting = NULL;
if (ProcessHelp(hDlg, message, wParam, lParam, HelpId)) return TRUE;
switch (message)
{
case WM_INITDIALOG:
if (lParam)
{
pDunSetting = (CDunSetting*)lParam;
//
// Setup the help ID appropriately
//
HelpId = ((pDunSetting->bTunnelDunSetting) ? IDH_VENTRY : IDH_DENTRY);
//
// Set the radio button to the correct choice
//
UINT uRadioButtonToSet;
if (pDunSetting->bPWEncrypt_MS)
{
uRadioButtonToSet = IDC_MS_ENCRYPTED_AUTH;
//
// Set the Data Encryption checkbox, note that data encryption requires MSChap
//
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_CHECK1, pDunSetting->bDataEncrypt));
}
else if (pDunSetting->bPWEncrypt)
{
uRadioButtonToSet = IDC_ENCRYPTED_AUTH;
}
else
{
uRadioButtonToSet = IDC_ANY_AUTH;
}
MYVERIFY(0 != CheckRadioButton(hDlg, IDC_ANY_AUTH, IDC_MS_ENCRYPTED_AUTH, uRadioButtonToSet));
if (pDunSetting->bTunnelDunSetting)
{
//
// Set the radio buttons for using PPTP or using L2TP depending on the setting...
//
if (pDunSetting->bUseDownLevelL2TP)
{
uRadioButtonToSet = IDC_USE_L2TP;
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_CHECK2, pDunSetting->bUsePskDownLevel));
}
else
{
uRadioButtonToSet = IDC_USE_PPTP;
}
MYVERIFY(0 != CheckRadioButton(hDlg, IDC_USE_PPTP, IDC_USE_L2TP, uRadioButtonToSet));
}
}
else
{
pDunSetting = NULL;
CMASSERTMSG(FALSE, TEXT("ProcessSecurityPopup -- NULL lParam passed to InitDialog. Dialog controls will all be set to off."));
}
EnableDisableDataEncryptCheckbox(hDlg);
EnableDisableUsePskCheckbox(hDlg);
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_MS_ENCRYPTED_AUTH:
case IDC_ENCRYPTED_AUTH:
case IDC_ANY_AUTH:
EnableDisableDataEncryptCheckbox(hDlg);
break;
case IDC_USE_L2TP:
case IDC_USE_PPTP:
EnableDisableUsePskCheckbox(hDlg);
break;
case IDOK:
MYDBGASSERT(pDunSetting);
if (pDunSetting)
{
pDunSetting->bDataEncrypt = IsDlgButtonChecked(hDlg, IDC_CHECK1); // if mschap isn't enabled we will write out zero for DataEncrypt
pDunSetting->bPWEncrypt_MS = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_MS_ENCRYPTED_AUTH));
pDunSetting->bPWEncrypt = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ENCRYPTED_AUTH));
pDunSetting->bUseDownLevelL2TP = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_USE_L2TP));
// IDC_CHECK2 can be disabled but still checked, thus if it's not enabled we need to
// explicitly set bUsePskDownLevel to FALSE
if (pDunSetting->bUseDownLevelL2TP)
{
pDunSetting->bUsePskDownLevel = IsDlgButtonChecked(hDlg, IDC_CHECK2); // if L2TP isn't enabled we will write out zero for UsePskDownLevel
}
else
{
pDunSetting->bUsePskDownLevel = FALSE;
}
}
EndDialog(hDlg, IDOK);
break;
case IDCANCEL:
EndDialog(hDlg, IDCANCEL);
break;
default:
break;
}
break;
}
return FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: EnableDisableEapPropertiesButton
//
// Synopsis: This function enables or disables the EAP properties button found
// on the Win2k specific security settings dialog. If the currently
// selected EAP has configuration UI then the properties button should
// be enabled. The function determines this by getting the EAPData
// structure pointer that is cached in the ItemData of the combobox.
// Note that the Properties button should also be disabled when EAP
// is disabled but that this function doesn't deal with that case.
//
// Arguments: HWND hDlg - window handle to the win2k security dialog
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void EnableDisableEapPropertiesButton(HWND hDlg)
{
BOOL bEnablePropButton = FALSE;
LRESULT lResult = SendDlgItemMessage(hDlg, IDC_EAP_TYPES, CB_GETCURSEL, 0, 0);
if (CB_ERR != lResult)
{
lResult = SendDlgItemMessage(hDlg, IDC_EAP_TYPES, CB_GETITEMDATA, (WPARAM)lResult, 0);
EAPData* pEAPData = (EAPData*)lResult;
if (pEAPData)
{
bEnablePropButton = (pEAPData->pszConfigDllPath && pEAPData->pszConfigDllPath[0]);
}
}
EnableWindow(GetDlgItem(hDlg, IDC_EAP_PROPERTIES), bEnablePropButton);
}
//+----------------------------------------------------------------------------
//
// Function: EnableAppropriateSecurityControls
//
// Synopsis: This function enables or disables all of the authorization
// protocol controls on the win2k security dialog. If EAP
// is selected then only the EAP combobox and potentially the
// EAP properties button should be enabled (depending on if the
// currently selected EAP supports configuration UI or not).
// If EAP is NOT selected then the EAP controls should be disabled
// and the other authorization checkboxes (PAP, SPAP, CHAP, etc.)
// should be enabled.
//
// Arguments: HWND hDlg - window handle to the win2k security dialog
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void EnableAppropriateSecurityControls(HWND hDlg)
{
BOOL bUseEAP = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_USE_EAP));
//
// If EAP is enabled then we need to disable all of the
// other security authorization protocols.
//
EnableWindow(GetDlgItem(hDlg, IDC_ALLOW_PAP), !bUseEAP);
EnableWindow(GetDlgItem(hDlg, IDC_ALLOW_SPAP), !bUseEAP);
EnableWindow(GetDlgItem(hDlg, IDC_ALLOW_CHAP), !bUseEAP);
EnableWindow(GetDlgItem(hDlg, IDC_ALLOW_MSCHAP), !bUseEAP);
EnableWindow(GetDlgItem(hDlg, IDC_ALLOW_MSCHAP2), !bUseEAP);
//
// If EAP is disabled then we need to enable the enable combobox
// and the EAP properties button.
//
EnableWindow(GetDlgItem(hDlg, IDC_EAP_TYPES), bUseEAP);
if (bUseEAP)
{
EnableDisableEapPropertiesButton(hDlg);
}
else
{
EnableWindow(GetDlgItem(hDlg, IDC_EAP_PROPERTIES), FALSE);
}
}
#define MAX_BLOB_CHARS_PER_LINE 128
//
// From ras\ui\common\nouiutil\noui.c
//
BYTE HexValue(IN CHAR ch)
/* Returns the value 0 to 15 of hexadecimal character 'ch'.
*/
{
if (ch >= '0' && ch <= '9')
return (BYTE )(ch - '0');
else if (ch >= 'A' && ch <= 'F')
return (BYTE )((ch - 'A') + 10);
else if (ch >= 'a' && ch <= 'f')
return (BYTE )((ch - 'a') + 10);
else
return 0;
}
//+----------------------------------------------------------------------------
//
// Function: ReadDunSettingsEapData
//
// Synopsis: Retrieves DUN setting for EAP config (opaque blob) data. The
// entry may span several lines and contain several EAP data blocks.
//
// Arguments: CIni *pIni - Ptr to ini object to be used.
// LPBYTE* ppbEapData - Address of pointer to store EapData, allocated here.
// LPDWORD pdwEapSize - Ptr to a DWORD to record the size of the data blob.
// DWORD dwCustomAuthKey - The EAP type that we are interested in.
//
// Returns: TRUE on success
//
// Note: CM expects blob data to be provided in numbered entries such as:
// CustomAuthData0=, CustomAuthData1=, CustomAuthData2=, etc.
//
// History: nickball Created 08/24/98
// nickball Handle multiple EAP data blocks in blob. 09/11/99
// quintinb modified not to use CIni 03/27/00
//
//+----------------------------------------------------------------------------
BOOL ReadDunSettingsEapData(LPCTSTR pszSection, LPBYTE* ppbEapData, LPDWORD pdwEapSize, const DWORD dwCustomAuthKey, LPCTSTR pszCmsFile)
{
CHAR *pchBuf = NULL;
CHAR szTmp[MAX_BLOB_CHARS_PER_LINE + 2];
CHAR szEntry[128];
int nLine = -1;
int nRead = -1;
int nTotal = 0;
LPBYTE pbEapBytes = NULL;
MYDBGASSERT(pszSection);
MYDBGASSERT(pszSection[0]);
MYDBGASSERT(ppbEapData);
MYDBGASSERT(pdwEapSize);
if ((NULL == pszSection) || (NULL == ppbEapData) || (NULL == pdwEapSize) || (TEXT('\0') == pszSection[0]))
{
return FALSE;
}
//
// Convert the Section and the CMS File to ANSI strings
//
BOOL bRet = FALSE;
LPSTR pszAnsiSection = WzToSzWithAlloc(pszSection);
LPSTR pszAnsiCmsFile = WzToSzWithAlloc(pszCmsFile);
if (!pszAnsiSection || !pszAnsiCmsFile)
{
bRet = FALSE;
goto exit;
}
//
// Read numbered entries until there are no more.
// Note: RAS blob doesn't exceed 64 chars, but can wrap over multiple lines
//
while (nRead)
{
//
// Read CustomAuthDataX where X is the number of entries
//
nLine++;
wsprintfA(szEntry, "%s%d", c_pszCmEntryDunServerCustomAuthData, nLine);
nRead = GetPrivateProfileStringA(pszAnsiSection, szEntry, "", szTmp, sizeof(szTmp), pszAnsiCmsFile);
if (nRead)
{
//
// If line exceeded 128 chars, it is considered corrupt
//
if (MAX_BLOB_CHARS_PER_LINE < nRead)
{
nTotal = 0;
break;
}
//
// Update our local master buffer with the latest fragment
//
if (nLine)
{
pchBuf = CmStrCatAllocA(&pchBuf, szTmp);
}
else
{
pchBuf = CmStrCpyAllocA(szTmp);
}
if (!pchBuf)
{
bRet = FALSE;
goto exit;
}
nTotal += nRead;
}
}
//
// At this point we should have the entire entry in pchBuf in HEX format
// Convert the buffer to byte format and store in supplied EAP buffer.
//
if (nTotal && !(nTotal & 1))
{
nTotal /= 2; // Only need half the hex char size
pbEapBytes = (BYTE *) CmMalloc(nTotal + 1);
if (!pbEapBytes)
{
goto exit;
}
CHAR *pch = pchBuf;
BYTE *pb = pbEapBytes;
while (*pch != '\0')
{
*pb = HexValue( *pch++ ) * 16;
*pb += HexValue( *pch++ );
++pb;
}
//
// Now we have the bytes, locate and extract the data block that we
// are after. Note: Multiple blocks are arrayed using the following
// header:
//
// typedef struct _EAP_CUSTOM_DATA
// {
// DWORD dwSignature;
// DWORD dwCustomAuthKey;
// DWORD dwSize;
// BYTE abdata[1];
// } EAP_CUSTOM_DATA;
//
EAP_CUSTOM_DATA *pCustomData = (EAP_CUSTOM_DATA *) pbEapBytes;
while (((LPBYTE) pCustomData - pbEapBytes) < nTotal)
{
if (pCustomData->dwCustomAuthKey == dwCustomAuthKey)
{
//
// Bingo! We have a match, first make sure that the indicated
// size isn't pointing out into space, then make a copy and
// run for the hills.
//
if (((LPBYTE) pCustomData - pbEapBytes) + sizeof(EAP_CUSTOM_DATA) + pCustomData->dwSize > (DWORD) nTotal)
{
MYDBGASSERT(FALSE);
goto exit;
}
*ppbEapData = (BYTE *) CmMalloc(pCustomData->dwSize);
if (*ppbEapData)
{
CopyMemory(*ppbEapData, pCustomData->abdata, pCustomData->dwSize);
*pdwEapSize = pCustomData->dwSize;
bRet = TRUE;
goto exit;
}
}
//
// Locate the next data block
//
pCustomData = (EAP_CUSTOM_DATA *) ((LPBYTE) pCustomData + sizeof(EAP_CUSTOM_DATA) + pCustomData->dwSize);
}
}
else if (0 == nTotal)
{
//
// No CustomAuthData, that is perfectly exceptable. MD5 challenge for instance doesn't require any
//
*ppbEapData = NULL;
*pdwEapSize = 0;
bRet = TRUE;
}
exit:
CmFree(pchBuf);
CmFree(pszAnsiSection);
CmFree(pszAnsiCmsFile);
CmFree(pbEapBytes);
return bRet;
}
//
// From ras\ui\common\nouiutil\noui.c
//
CHAR HexChar(IN BYTE byte)
/* Returns an ASCII hexidecimal character corresponding to 0 to 15 value,
** 'byte'.
*/
{
const CHAR* pszHexDigits = "0123456789ABCDEF";
if (byte >= 0 && byte < 16)
return pszHexDigits[ byte ];
else
return '0';
}
//+----------------------------------------------------------------------------
//
// Function: WriteDunSettingsEapData
//
// Synopsis: This function writes out the CustomAuthData key of the EAP settings
// to the given section and CMS file. Since CM expects the EAP data
// to have the RAS EAP header on it (the header that RAS adds when it
// puts the EAP data in the phonebook) and thus we need to add this
// to the EAP blob before writing it to the CMS.
//
// Arguments: LPCTSTR pszSection - section name to write the CustomAuthData to
// CDunSetting* pDunSetting - Dun settings data
// LPCTSTR pszCmsFile - cms file to write the data to
//
// Returns: HRESULT - standard COM style error codes
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
HRESULT WriteDunSettingsEapData(LPCTSTR pszSection, CDunSetting* pDunSetting, LPCTSTR pszCmsFile)
{
if ((NULL == pszSection) || (NULL == pDunSetting) || (NULL == pszCmsFile) ||
(TEXT('\0') == pszSection[0]) || (TEXT('\0') == pszCmsFile[0]))
{
return E_INVALIDARG;
}
//
// Make sure to erase any existing lines just in case the existing data is longer
// than our current data. If we leave lines around that don't need to be there then
// the EAP data will be invalid.
//
HRESULT hr = EraseDunSettingsEapData(pszSection, pszCmsFile);
//
// Check to see if we need to do anything. Not all EAP's require custom data so
// let's not try to write it out unless we have some.
//
if (pDunSetting->dwCustomAuthDataSize && pDunSetting->pCustomAuthData)
{
//
// We need to add the EAP_CUSTOM_DATA header to the
// data returned from the EAP because this is the format
// that CM expects to find it in (the format it would be in
// if an Admin copied it by hand).
//
hr = S_OK;
DWORD dwSize = pDunSetting->dwCustomAuthDataSize + sizeof(EAP_CUSTOM_DATA);
EAP_CUSTOM_DATA* pEAPCustomData = (EAP_CUSTOM_DATA*)CmMalloc(dwSize);
LPSTR pszAnsiSection = WzToSzWithAlloc(pszSection);
LPSTR pszAnsiCmsFile = WzToSzWithAlloc(pszCmsFile);
if (pEAPCustomData && pszAnsiSection && pszAnsiCmsFile)
{
pEAPCustomData->dwSignature = EAP_CUSTOM_KEY;
pEAPCustomData->dwCustomAuthKey = pDunSetting->dwCustomAuthKey;
pEAPCustomData->dwSize = pDunSetting->dwCustomAuthDataSize;
CopyMemory(pEAPCustomData->abdata, pDunSetting->pCustomAuthData, pDunSetting->dwCustomAuthDataSize);
CHAR szOutput[MAX_BLOB_CHARS_PER_LINE+1];
CHAR szAnsiKeyName[MAX_BLOB_CHARS_PER_LINE];
CHAR* pszOutput;
LPBYTE pCurrentByte = (LPBYTE)pEAPCustomData;
int iCount = 0;
int iLineNum = 0;
pszOutput = szOutput;
while (pCurrentByte < ((LPBYTE)pEAPCustomData + dwSize))
{
*pszOutput++ = HexChar( (BYTE )(*pCurrentByte / 16) );
*pszOutput++ = HexChar( (BYTE )(*pCurrentByte % 16) );
pCurrentByte++;
iCount = iCount + 2; // keep track of number of chars in ansi output buffer
if ((MAX_BLOB_CHARS_PER_LINE == iCount) || (pCurrentByte == ((LPBYTE)pEAPCustomData + dwSize)))
{
*pszOutput = '\0';
wsprintfA(szAnsiKeyName, "%s%d", c_pszCmEntryDunServerCustomAuthData, iLineNum);
MYVERIFY(0 != WritePrivateProfileStringA(pszAnsiSection, szAnsiKeyName, szOutput, pszAnsiCmsFile));
pszOutput = szOutput;
iCount = 0;
iLineNum++;
}
}
}
else
{
hr = E_OUTOFMEMORY;
}
CmFree(pEAPCustomData);
CmFree(pszAnsiCmsFile);
CmFree(pszAnsiSection);
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Function: GetEAPDataFromUser
//
// Synopsis: This function is called when the user hits the properties button
// for EAP configuration. This function gets the EAP configuration
// UI path from the EAPData structure cached in the Combobox Item data
// and tries to call the configuration UI. If the user configures the
// EAP then the new EAP data and data size are set in the EAPData
// struct for the combobox. If the user cancels then nothing is changed.
// Note that when the user hits OK on the win2k security dialog the EAP
// data will be retrieved from the EAPData struct and set in the
// actual DUN setting.
//
// Arguments: HWND hDlg - dialog window handle
// UINT uCtrlId - control ID of the EAP combobox
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void GetEAPDataFromUser(HWND hDlg, UINT uCtrlId)
{
MYDBGASSERT(hDlg && uCtrlId);
if (hDlg && uCtrlId)
{
LRESULT lResult = SendDlgItemMessage(hDlg, uCtrlId, CB_GETCURSEL, 0, 0);
MYDBGASSERT(CB_ERR != lResult);
if (CB_ERR != lResult)
{
lResult = SendDlgItemMessage(hDlg, uCtrlId, CB_GETITEMDATA, (WPARAM)lResult, 0);
EAPData* pEAPData = (EAPData*)lResult;
if (pEAPData && pEAPData->pszConfigDllPath && pEAPData->pszConfigDllPath[0])
{
HINSTANCE hEapConfigDll = LoadLibrary(pEAPData->pszConfigDllPath);
if (hEapConfigDll)
{
typedef DWORD (WINAPI *RasEapInvokeConfigUIProc)(DWORD, HWND, DWORD, BYTE*, DWORD, BYTE**, DWORD*);
typedef DWORD (WINAPI *RasEapFreeMemoryProc)(BYTE*);
const char* const c_pszRasEapFreeMemory = "RasEapFreeMemory";
const char* const c_pszRasEapInvokeConfigUI = "RasEapInvokeConfigUI";
RasEapFreeMemoryProc pfnRasEapFreeMemory = (RasEapFreeMemoryProc)GetProcAddress(hEapConfigDll, c_pszRasEapFreeMemory);
RasEapInvokeConfigUIProc pfnRasEapInvokeConfigUI = (RasEapInvokeConfigUIProc)GetProcAddress(hEapConfigDll, c_pszRasEapInvokeConfigUI);
if (pfnRasEapFreeMemory && pfnRasEapInvokeConfigUI)
{
DWORD dwNewSize = 0;
BYTE* pNewData = NULL;
DWORD dwReturn = pfnRasEapInvokeConfigUI(pEAPData->dwCustomAuthKey, hDlg, 0, pEAPData->pCustomAuthData,
pEAPData->dwCustomAuthDataSize, &pNewData, &dwNewSize);
if (NO_ERROR == dwReturn)
{
CmFree(pEAPData->pCustomAuthData);
pEAPData->pCustomAuthData = (LPBYTE)CmMalloc(dwNewSize);
if (pEAPData->pCustomAuthData)
{
pEAPData->dwCustomAuthDataSize = dwNewSize;
CopyMemory(pEAPData->pCustomAuthData, pNewData, dwNewSize);
}
else
{
pEAPData->dwCustomAuthDataSize = 0;
pEAPData->pCustomAuthData = NULL;
CMASSERTMSG(FALSE, TEXT("GetEAPDataFromUser -- CmMalloc failed."));
}
MYVERIFY(NO_ERROR == pfnRasEapFreeMemory(pNewData));
}
else if (ERROR_CANCELLED != dwReturn)
{
CMTRACE3(TEXT("EAP %d (%s) failed with return code %d"), pEAPData->dwCustomAuthKey, pEAPData->pszConfigDllPath, dwReturn);
CMASSERTMSG(FALSE, TEXT("GetEAPDataFromUser -- pfnRasEapInvokeConfigUI from EAP dll failed."));
}
}
else
{
CMASSERTMSG(FALSE, TEXT("GetEAPDataFromUser -- GetProcAddressFailed on the EAP dll."));
}
}
else
{
CMTRACE2(TEXT("Failed to load EAP %d (%s)"), pEAPData->dwCustomAuthKey, pEAPData->pszConfigDllPath);
CMASSERTMSG(FALSE, TEXT("GetEAPDataFromUser -- Unable to load the specified EAP Dll."));
}
}
}
}
}
int MapEncryptionTypeToComboId(DWORD dwEncryptionType)
{
int iReturn;
switch(dwEncryptionType)
{
case ET_None:
iReturn = 0;
break;
case ET_RequireMax:
case ET_Require:
iReturn = 1;
break;
case ET_Optional:
default:
iReturn = 2;
break;
}
return iReturn;
}
DWORD MapComboIdToEncryptionType(INT_PTR iComboIndex)
{
DWORD dwReturn;
switch(iComboIndex)
{
case 0:
dwReturn = ET_None;
break;
case 1:
dwReturn = ET_Require; // note that we never set require max
break;
case 2:
default:
dwReturn = ET_Optional;
break;
}
return dwReturn;
}
//+----------------------------------------------------------------------------
//
// Function: EnablePskCheckboxForL2TP
//
// Synopsis: This function enables the PSK checkbox
//
// Arguments: HWND hDlg - window handle
//
// Returns: Nothing
//
// History: quintinb Created 09/12/01
//
//+----------------------------------------------------------------------------
void EnablePskCheckboxForL2TP(HWND hDlg)
{
BOOL bEnable = FALSE;
DWORD dwVpnStrategy = (DWORD)SendDlgItemMessage(hDlg, IDC_VPN_TYPE, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
if (CB_ERR != dwVpnStrategy)
{
dwVpnStrategy += 1; // adjust for not having automatic in the list.
if ((VS_L2tpFirst == dwVpnStrategy) || (VS_L2tpOnly == dwVpnStrategy))
{
bEnable = TRUE;
}
}
//
// Enable the psk checkbox if an L2TP protocol is selected but disable it if
// PPTP is the primary protocol (PPTP first or PPTP only).
//
EnableWindow(GetDlgItem(hDlg, IDC_USE_PSK), bEnable);
}
//+----------------------------------------------------------------------------
//
// Function: ProcessWin2kSecurityPopup
//
// Synopsis: This function processes messages for the Win2k+ security dialog.
// This dialog contains configuration UI for all of the advanced
// settings allowed by Win2k (EAP, PAP, SPAP, etc plus encryption
// type and vpn strategy).
//
// Arguments: HWND hDlg - window handle to the dialog
// UINT message - the current message to process
// WPARAM wParam - wParam see individual message type for details
// LPARAM lParam - lParam see individual message type for details
//
// Returns: INT_PTR - TRUE if the message was completely handled
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
INT_PTR APIENTRY ProcessWin2kSecurityPopup(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
static DWORD_PTR HelpId = 0;
static CDunSetting* pDunSetting = NULL;
SetDefaultGUIFont(hDlg, message, IDC_ENCRYPTION_TYPE);
SetDefaultGUIFont(hDlg, message, IDC_EAP_TYPES);
SetDefaultGUIFont(hDlg, message, IDC_VPN_TYPE);
if (ProcessHelp(hDlg, message, wParam, lParam, HelpId)) return TRUE;
switch (message)
{
case WM_INITDIALOG:
if (lParam)
{
pDunSetting = (CDunSetting*)lParam;
//
// Setup the help ID appropriately
//
HelpId = ((pDunSetting->bTunnelDunSetting) ? IDH_VENTRY : IDH_DENTRY);
//
// Load and add the strings to the Data Encryption combobox
//
LPTSTR pszString;
for (int i = BASE_ENCRYPT_TYPE_ID; i < (BASE_ENCRYPT_TYPE_ID + NUM_ENCRYPT_TYPES); i++)
{
pszString = CmLoadString(g_hInstance, i);
MYDBGASSERT(pszString);
if (pszString)
{
SendDlgItemMessage(hDlg, IDC_ENCRYPTION_TYPE, CB_ADDSTRING, 0, (LPARAM)pszString);
CmFree(pszString);
}
}
//
// Now pick the type of encryption the user has selected
//
MYVERIFY(CB_ERR != SendDlgItemMessage(hDlg, IDC_ENCRYPTION_TYPE, CB_SETCURSEL, (WPARAM)MapEncryptionTypeToComboId(pDunSetting->dwEncryptionType), (LPARAM)0));
//
// Enumerate all of the available EAP's on the machine
//
MYVERIFY(SUCCEEDED(HrAddAvailableEAPsToCombo(hDlg, IDC_EAP_TYPES, pDunSetting)));
//
// Select the appropriate EAP as necessary
//
SelectAppropriateEAP(hDlg, IDC_EAP_TYPES, pDunSetting);
//
// Figure out what authentication protocols the user wants to allow.
// Note that if we are doing EAP then that is all we allow them to do
// and the other settings will be ignored. Also note that we don't have
// UI for w95CHAP but we won't touch the setting if it exists.
//
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_ALLOW_PAP, pDunSetting->bAllowPap));
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_ALLOW_SPAP, pDunSetting->bAllowSpap));
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_ALLOW_CHAP, pDunSetting->bAllowChap));
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_ALLOW_MSCHAP, pDunSetting->bAllowMsChap));
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_ALLOW_MSCHAP2, pDunSetting->bAllowMsChap2));
if (pDunSetting->bAllowEap)
{
MYVERIFY(0 != CheckRadioButton(hDlg, IDC_USE_EAP, IDC_ALLOWED_PROTOCOLS, IDC_USE_EAP));
}
else
{
MYVERIFY(0 != CheckRadioButton(hDlg, IDC_USE_EAP, IDC_ALLOWED_PROTOCOLS, IDC_ALLOWED_PROTOCOLS));
}
//
// Note that the VPN controls do not exist unless we have a Tunnel Dun Setting and are
// thus using the tunnel dun setting dialog.
//
if (pDunSetting->bTunnelDunSetting)
{
//
// Load and add the Vpn type string to the vpn type combobox
//
for (int i = BASE_VPN_TYPE_ID; i < (BASE_VPN_TYPE_ID + NUM_VPN_TYPES); i++)
{
pszString = CmLoadString(g_hInstance, i);
MYDBGASSERT(pszString);
if (pszString)
{
SendDlgItemMessage(hDlg, IDC_VPN_TYPE, CB_ADDSTRING, 0, (LPARAM)pszString);
CmFree(pszString);
}
}
//
// Pick the type of vpn strategy the user has selected
//
MYDBGASSERT(pDunSetting->dwVpnStrategy != 0);
MYVERIFY(CB_ERR != SendDlgItemMessage(hDlg, IDC_VPN_TYPE, CB_SETCURSEL, (WPARAM)(pDunSetting->dwVpnStrategy - 1), (LPARAM)0));
//
// Fill in the PSK checkbox as needed
//
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_USE_PSK, pDunSetting->bUsePskOnWin2kPlus));
}
//
// We only want either the EAP controls or the non-EAP auth controls
// enabled at once. Thus figure out which to enable/disable
//
EnableAppropriateSecurityControls(hDlg);
EnablePskCheckboxForL2TP(hDlg);
}
else
{
pDunSetting = NULL;
CMASSERTMSG(FALSE, TEXT("ProcessWin2kSecurityPopup -- NULL lParam passed to InitDialog. Dialog controls will all be set to off."));
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_EAP_PROPERTIES:
GetEAPDataFromUser(hDlg, IDC_EAP_TYPES);
break;
case IDOK:
MYDBGASSERT(pDunSetting);
if (pDunSetting)
{
//
// Since we are storing the settings directly in the data struct given to us, first
// verify that the authentication protocol and the encryption type match up properly.
// Otherwise a user could modify settings, hit OK, we tell them the settings are
// inappropriate and they hit cancel. Any settings we modifed before we did the
// verification would then actually be modified. To avoid that check to make sure
// we have at least one security protocol checked before continuing.
//
BOOL bHasAuthProtocol = FALSE;
for (int i = BASE_AUTH_CONTROL_ID; i < (BASE_AUTH_CONTROL_ID + NUM_AUTH_TYPES); i++)
{
if (BST_CHECKED == IsDlgButtonChecked(hDlg, i))
{
bHasAuthProtocol = TRUE;
break;
}
}
if ((FALSE == bHasAuthProtocol) && (BST_UNCHECKED == IsDlgButtonChecked(hDlg, IDC_USE_EAP)))
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_NEED_AUTH_PROTOCOL, MB_OK | MB_ICONSTOP));
return TRUE;
}
//
// Next we need to decide whether the user is using EAP or not. Retrieving the data
// for the EAP they have picked from the combo (if any) will help us decide whether the
// auth protocol they choose matches up with the encryption settings they asked for.
//
EAPData* pEAPData = NULL;
if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_USE_EAP))
{
//
// Get the EAP Type and the data associated with it.
//
LRESULT lResult = SendDlgItemMessage(hDlg, IDC_EAP_TYPES, CB_GETCURSEL, 0, 0);
MYDBGASSERT(CB_ERR != lResult);
if (CB_ERR != lResult)
{
lResult = SendDlgItemMessage(hDlg, IDC_EAP_TYPES, CB_GETITEMDATA, (WPARAM)lResult, 0);
pEAPData = (EAPData*)lResult;
if (pEAPData && pEAPData->bMustConfig && (NULL == pEAPData->pCustomAuthData))
{
LPTSTR pszMsg = CmFmtMsg(g_hInstance, IDS_EAP_NEEDS_CONFIG, pEAPData->pszFriendlyName);
if (pszMsg)
{
MessageBox(hDlg, pszMsg, g_szAppTitle, MB_OK | MB_ICONSTOP);
CmFree(pszMsg);
}
else
{
CMASSERTMSG(FALSE, TEXT("ProcessWin2kSecurityPopup -- CmMalloc failed!"));
}
HWND hButton = GetDlgItem(hDlg, IDC_EAP_PROPERTIES);
if (hButton && IsWindowEnabled(hButton))
{
SetFocus(hButton);
}
return TRUE;
}
}
}
//
// Now get the encryption type that the user selected. Note that in order to negotiate
// encryption we must have EAP or some sort of MSCHAP.
//
LRESULT lResult = (DWORD)SendDlgItemMessage(hDlg, IDC_ENCRYPTION_TYPE, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
DWORD dwTemp = MapComboIdToEncryptionType(lResult);
MYDBGASSERT(ET_RequireMax != dwTemp); // we should never be setting require max
if ((ET_Require == dwTemp) || (ET_Optional == dwTemp))
{
//
// If the user is using EAP, then the EAP type they picked must support
// encryption. Otherwise, the user must not be using EAP and they must
// be using some sort of MSChap. The following could be expressed more
// succintly, but there is no sense in confusing the issue.
//
BOOL bEncryptionAllowed = FALSE;
if (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_USE_EAP))
{
if (pEAPData)
{
bEncryptionAllowed = pEAPData->bSupportsEncryption;
}
}
else
{
bEncryptionAllowed = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_MSCHAP)) ||
(BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_MSCHAP2));
}
//
// Warn the user if he selected one of these three authentication methods,
// he needs to make a correction since he requires encryption, but we don't
// want to show a warning when using 'L2TP Only'.
//
if ((BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOWED_PROTOCOLS)) &&
((BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_PAP)) ||
(BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_SPAP)) ||
(BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_CHAP))))
{
DWORD dwVpnStrategyTemp = (DWORD)SendDlgItemMessage(hDlg, IDC_VPN_TYPE, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
if (CB_ERR == dwVpnStrategyTemp)
{
CMASSERTMSG(FALSE, TEXT("ProcessWin2kSecurityPopup -- CB_ERR returned for VPN strategy."));
dwVpnStrategyTemp = VS_PptpFirst;
}
else
{
//
// Adjust Vpn Strategy because we no longer offer Automatic as a choice
//
dwVpnStrategyTemp +=1;
}
if (VS_L2tpOnly != dwVpnStrategyTemp)
{
if (IDNO == ShowMessage(hDlg, IDS_NEED_EAP_OR_MSCHAP, MB_YESNO | MB_ICONSTOP))
{
CheckDlgButton(hDlg, IDC_ALLOW_PAP, FALSE);
CheckDlgButton(hDlg, IDC_ALLOW_SPAP, FALSE);
CheckDlgButton(hDlg, IDC_ALLOW_CHAP, FALSE);
return TRUE;
}
}
}
else
{
if (FALSE == bEncryptionAllowed)
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_EAP_HAS_NO_ECRYPTION, MB_OK | MB_ICONSTOP));
return TRUE;
}
}
}
//
// Now save the actual settings
//
pDunSetting->dwEncryptionType = dwTemp;
if (pEAPData)
{
//
// Now lets update pDunSetting with the actual data. Note that we are past the
// last place we could throw an error to the user and thus it is okay to touch
// the pDunSetting data (even if the user got an error and then hit cancel we will
// leave their previous data untouched). Note that we don't want to touch the existing
// data if we don't have the EAP installed because we know that we couldn't have
// actually changed the data.
//
pDunSetting->bAllowEap = TRUE;
if (FALSE == pEAPData->bNotInstalled)
{
CmFree(pDunSetting->pCustomAuthData);
pDunSetting->dwCustomAuthKey = pEAPData->dwCustomAuthKey;
pDunSetting->pCustomAuthData = pEAPData->pCustomAuthData;
pDunSetting->dwCustomAuthDataSize = pEAPData->dwCustomAuthDataSize;
//
// Now NULL out the pEapData entry, this saves us from having to
// allocate mem and copy to pDunSetting but keeps the code
// that cleans up the EapData structs from freeing our data
//
pEAPData->pCustomAuthData = NULL;
pEAPData->dwCustomAuthDataSize = 0;
}
}
else
{
pDunSetting->bAllowEap = FALSE;
}
//
// Get the non-EAP protocols. Note that if the user selected EAP we will clear
// these before writing them out.
//
pDunSetting->bAllowPap = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_PAP));
pDunSetting->bAllowSpap = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_SPAP));
pDunSetting->bAllowChap = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_CHAP));
pDunSetting->bAllowMsChap = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_MSCHAP));
pDunSetting->bAllowMsChap2 = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_ALLOW_MSCHAP2));
if (pDunSetting->bTunnelDunSetting)
{
pDunSetting->dwVpnStrategy = (DWORD)SendDlgItemMessage(hDlg, IDC_VPN_TYPE, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
if (CB_ERR == pDunSetting->dwVpnStrategy)
{
CMASSERTMSG(FALSE, TEXT("ProcessWin2kSecurityPopup -- CB_ERR returned for VPN strategy."));
pDunSetting->dwVpnStrategy = VS_PptpFirst;
}
else
{
//
// Adjust Vpn Strategy because we no longer offer Automatic as a choice
//
pDunSetting->dwVpnStrategy += 1;
MYDBGASSERT((pDunSetting->dwVpnStrategy >= VS_PptpOnly) && (pDunSetting->dwVpnStrategy <= VS_L2tpFirst));
}
if ((VS_L2tpFirst == pDunSetting->dwVpnStrategy) || (VS_L2tpOnly == pDunSetting->dwVpnStrategy))
{
pDunSetting->bUsePskOnWin2kPlus = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_USE_PSK));
}
else
{
pDunSetting->bUsePskOnWin2kPlus = FALSE;
}
}
}
FreeEapData(hDlg, IDC_EAP_TYPES);
EndDialog(hDlg, IDOK);
break;
case IDCANCEL:
FreeEapData(hDlg, IDC_EAP_TYPES);
EndDialog(hDlg, IDCANCEL);
break;
case IDC_USE_EAP:
MYDBGASSERT(pDunSetting);
if (pDunSetting)
{
SelectAppropriateEAP(hDlg, IDC_EAP_TYPES, pDunSetting);
}
case IDC_ALLOWED_PROTOCOLS:
EnableAppropriateSecurityControls(hDlg);
break;
case IDC_EAP_TYPES:
if (HIWORD(wParam) == CBN_SELCHANGE)
{
EnableDisableEapPropertiesButton(hDlg);
}
break;
case IDC_VPN_TYPE:
if (HIWORD(wParam) == CBN_SELCHANGE)
{
EnablePskCheckboxForL2TP(hDlg);
}
break;
default:
break;
}
break;
}
return FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: EnableDisableSecurityButtons
//
// Synopsis: This function determines which of the two configure buttons
// should be enabled. The configure buttons allow the user to
// configure the security settings of the DUN settings. There is
// one button for platform independent security settings and one for
// win2k+ security settings.
//
// Arguments: HWND hDlg - window handle to the general property sheet
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void EnableDisableSecurityButtons(HWND hDlg)
{
INT_PTR nResult = SendDlgItemMessage(hDlg, IDC_COMBO1, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
if (CB_ERR == nResult)
{
nResult = 0;
}
//
// Disable the Win2k config button if the first selection is chosen
//
EnableWindow(GetDlgItem(hDlg, IDC_CONFIG_WIN2K), (0 != nResult));
//
// Disable the standard config button if the last selection is chosen
//
EnableWindow(GetDlgItem(hDlg, IDC_CONFIG_ALL), (2 != nResult));
}
//+----------------------------------------------------------------------------
//
// Function: GeneralPropSheetProc
//
// Synopsis: This function processes messages for General property sheet of
// the DUN settings UI. This property sheet holds UI for configuring
// the name of the DUN setting and dialup scripting.
//
// Arguments: HWND hDlg - window handle to the dialog
// UINT message - the current message to process
// WPARAM wParam - wParam see individual message type for details
// LPARAM lParam - lParam see individual message type for details
//
// Returns: INT_PTR - TRUE if the message was completely handled
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
INT_PTR APIENTRY GeneralPropSheetProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
NMHDR* pnmHeader = (NMHDR*)lParam;
INT_PTR nResult;
static DWORD_PTR HelpId = 0;
static ListBxList* pListEntry = NULL;
static CDunSetting* pDunSetting = NULL;
SetDefaultGUIFont(hDlg, message, IDC_EDIT1);
SetDefaultGUIFont(hDlg, message, IDC_EDIT2);
if (ProcessHelp(hDlg, message, wParam, lParam, HelpId)) return TRUE;
switch (message)
{
case WM_INITDIALOG:
if (lParam)
{
PROPSHEETPAGE* pPropSheetPage = (PROPSHEETPAGE*)lParam;
if (pPropSheetPage->lParam)
{
pListEntry = (ListBxList*)pPropSheetPage->lParam;
pDunSetting = (CDunSetting*)pListEntry->ListBxData;
if (pListEntry && pDunSetting)
{
//
// Setup the help ID appropriately...
//
HelpId = ((pDunSetting->bTunnelDunSetting) ? IDH_VENTRY : IDH_DENTRY);
if (pListEntry->szName[0])
{
MYVERIFY(TRUE == SendMessage(GetDlgItem(hDlg, IDC_EDIT1), WM_SETTEXT, 0, (LPARAM)pListEntry->szName));
EnableWindow(GetDlgItem(hDlg, IDC_EDIT1), FALSE); // don't allow the user to edit the name
}
//
// Now lets set the disable file and printer sharing checkbox and the network logon checkbox
//
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_CHECK1, pDunSetting->bSecureLocalFiles));
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_CHECK2, pDunSetting->bNetworkLogon));
if (pDunSetting->szScript[0])
{
MYVERIFY(TRUE == SendMessage(GetDlgItem(hDlg, IDC_EDIT2), WM_SETTEXT, 0, (LPARAM)GetName(pDunSetting->szScript)));
}
//
// If this is a VPN DUN setting, then hide the script controls
//
if (pDunSetting->bTunnelDunSetting)
{
ShowWindow(GetDlgItem(hDlg, IDC_SCRIPT_LABEL), SW_HIDE);
ShowWindow(GetDlgItem(hDlg, IDC_EDIT2), SW_HIDE);
ShowWindow(GetDlgItem(hDlg, IDC_BUTTON1), SW_HIDE);
}
}
else
{
CMASSERTMSG(FALSE, TEXT("GeneralPropSheetProc -- pListEntry or pDunSetting are NULL"));
}
}
else
{
pListEntry = NULL;
pDunSetting = NULL;
CMASSERTMSG(FALSE, TEXT("GeneralPropSheetProc -- NULL lParam passed to InitDialog. Dialog controls will all be set to off."));
}
}
else
{
pListEntry = NULL;
pDunSetting = NULL;
CMASSERTMSG(FALSE, TEXT("GeneralPropSheetProc -- NULL PropSheetPage pointer passed for lParam."));
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_BUTTON1: // browse button
if (pDunSetting)
{
UINT uScpFilter = IDS_SCPFILTER;
TCHAR* szScpMask = TEXT("*.scp");
MYVERIFY(0 != DoBrowse(hDlg, &uScpFilter, &szScpMask, 1, IDC_EDIT2,
TEXT("scp"), pDunSetting->szScript));
}
break;
}
break;
case WM_NOTIFY:
if (NULL == pnmHeader)
{
return FALSE;
}
switch (pnmHeader->code)
{
case PSN_APPLY:
if (pListEntry && pDunSetting)
{
//
// Get the name of the entry
//
nResult = GetTextFromControl(hDlg, IDC_EDIT1, pListEntry->szName, MAX_PATH, TRUE); // bDisplayError == TRUE
if (-1 == nResult)
{
//
// If we read in a string we cannot convert from the cms file and then the user editted the entry
// then the edit control may contain "bad" data but the user won't be able to edit it. Since this
// is extremely unlikely we won't add special handling for it other than to prevent the focus from
// being set to a disabled control.
//
if (IsWindowEnabled(GetDlgItem(hDlg, IDC_EDIT1)))
{
SetFocus(GetDlgItem(hDlg, IDC_EDIT1));
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
return TRUE;
}
//
// Now, let's trim the name and make sure it isn't empty
//
CmStrTrim(pListEntry->szName);
if ((TEXT('\0') == pListEntry->szName[0]) || (0 == nResult))
{
ShowMessage(hDlg, IDS_NEED_DUN_NAME, MB_OK);
if (IsWindowEnabled(GetDlgItem(hDlg, IDC_EDIT1)))
{
SetFocus(GetDlgItem(hDlg, IDC_EDIT1));
}
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
return TRUE;
}
//
// Get the values for the Secure local files and the network logon checkboxes
//
pDunSetting->bSecureLocalFiles = IsDlgButtonChecked(hDlg, IDC_CHECK1);
pDunSetting->bNetworkLogon = IsDlgButtonChecked(hDlg, IDC_CHECK2);
//
// Get and verify the script
//
if (FALSE == pDunSetting->bTunnelDunSetting)
{
if (!VerifyFile(hDlg, IDC_EDIT2, pDunSetting->szScript, TRUE))
{
SetFocus(GetDlgItem(hDlg, IDC_EDIT2));
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE);
return TRUE;
}
}
break;
}
}
break;
default:
return FALSE;
}
return FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: SecurityPropSheetProc
//
// Synopsis: This function processes messages for Security property sheet of
// the DUN settings UI. This property sheet holds UI for configuring
// how the user wants their security settings applied.
//
// Arguments: HWND hDlg - window handle to the dialog
// UINT message - the current message to process
// WPARAM wParam - wParam see individual message type for details
// LPARAM lParam - lParam see individual message type for details
//
// Returns: INT_PTR - TRUE if the message was completely handled
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
INT_PTR APIENTRY SecurityPropSheetProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
NMHDR* pnmHeader = (NMHDR*)lParam;
INT_PTR nResult;
static DWORD_PTR HelpId = 0;
static ListBxList* pListEntry = NULL;
static CDunSetting* pDunSetting = NULL;
static fUpdateVPNStrategy = TRUE;
SetDefaultGUIFont(hDlg, message, IDC_COMBO1);
if (ProcessHelp(hDlg, message, wParam, lParam, HelpId)) return TRUE;
switch (message)
{
case WM_INITDIALOG:
if (lParam)
{
PROPSHEETPAGE* pPropSheetPage = (PROPSHEETPAGE*)lParam;
fUpdateVPNStrategy = TRUE;
if (pPropSheetPage->lParam)
{
pListEntry = (ListBxList*)pPropSheetPage->lParam;
pDunSetting = (CDunSetting*)pListEntry->ListBxData;
if (pListEntry && pDunSetting) // this will give a big visual clue that something is wrong
{
//
// Setup the help ID appropriately
//
HelpId = ((pDunSetting->bTunnelDunSetting) ? IDH_VENTRY : IDH_DENTRY);
//
// Load and set the strings for the combo box
//
LPTSTR pszString;
for (int i = BASE_SECURITY_SCENARIO_ID; i < (BASE_SECURITY_SCENARIO_ID + NUM_SECURITY_SCENARIOS); i++)
{
pszString = CmLoadString(g_hInstance, i);
MYDBGASSERT(pszString);
if (pszString)
{
SendDlgItemMessage(hDlg, IDC_COMBO1, CB_ADDSTRING, 0, (LPARAM)pszString);
CmFree(pszString);
}
}
//
// Now figure out which selection to pick
//
MYVERIFY(CB_ERR != SendDlgItemMessage(hDlg, IDC_COMBO1, CB_SETCURSEL, (WPARAM)(pDunSetting->iHowToHandleSecuritySettings), (LPARAM)0));
EnableDisableSecurityButtons(hDlg);
}
else
{
CMASSERTMSG(FALSE, TEXT("SecurityPropSheetProc -- pListEntry or pDunSetting is NULL"));
}
}
else
{
pListEntry = NULL;
pDunSetting = NULL;
CMASSERTMSG(FALSE, TEXT("SecurityPropSheetProc -- NULL lParam passed to InitDialog. Dialog controls will all be set to off."));
}
}
else
{
pListEntry = NULL;
pDunSetting = NULL;
CMASSERTMSG(FALSE, TEXT("SecurityPropSheetProc -- NULL PropSheetPage pointer passed for lParam."));
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_CONFIG_ALL:
{
UINT uDialogId = pDunSetting->bTunnelDunSetting ? IDD_VPN_SECURITY_POPUP: IDD_DUN_SECURITY_POPUP;
nResult = DialogBoxParam(NULL, MAKEINTRESOURCE(uDialogId), hDlg, ProcessSecurityPopup, (LPARAM)pDunSetting);
}
break;
case IDC_CONFIG_WIN2K:
if (pDunSetting)
{
UINT uDialogId = pDunSetting->bTunnelDunSetting ? IDD_WIN2K_SECURITY_TUNNEL_POPUP: IDD_WIN2K_SECURITY_POPUP;
nResult = DialogBoxParam(NULL, MAKEINTRESOURCE(uDialogId), hDlg, ProcessWin2kSecurityPopup, (LPARAM)pDunSetting);
if (IDOK == nResult)
{
fUpdateVPNStrategy = FALSE;
}
}
break;
case IDC_COMBO1: // how does the user want the security settings applied
if (HIWORD(wParam) == CBN_SELCHANGE)
{
EnableDisableSecurityButtons(hDlg);
}
break;
}
break;
case WM_NOTIFY:
if (NULL == pnmHeader)
{
return FALSE;
}
switch (pnmHeader->code)
{
case PSN_APPLY:
if (pListEntry && pDunSetting)
{
//
// Figure out if the Admin wanted us to enforce the Win2k custom security flags or not
//
pDunSetting->iHowToHandleSecuritySettings = (int)SendDlgItemMessage(hDlg, IDC_COMBO1, CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
break;
}
}
break;
default:
return FALSE;
}
return FALSE;
}
//+----------------------------------------------------------------------------
//
// Function: CreateNetworkingEntryPropertySheet
//
// Synopsis: This function creates and launches the Networking DUN entry
// property sheet which allows networking entry configuration.
//
// Arguments: HINSTANCE hInstance - instance handle for resources
// HWND hWizard - window handle of the current CMAK wizard page
// LPARAM lParam - initialization parameter passed to each propsheet page
// BOOL bEdit - whether we are launching the property sheet to edit
// an existing entry or add a new one (affects the title).
//
// Returns: int - returns a positive value if successful, -1 on error
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
INT_PTR CreateNetworkingEntryPropertySheet(HINSTANCE hInstance, HWND hWizard, LPARAM lParam, BOOL bEdit, BOOL bUseVpnTitle)
{
PROPSHEETPAGE psp[3];
PROPSHEETHEADER psh = {0};
LPTSTR pszCaption = NULL;
INT_PTR iReturn = -1;
UINT uTitleStringId;
//
// Check the params, note that lParam could be NULL
//
if ((NULL == hInstance) || (NULL == hWizard))
{
CMASSERTMSG(FALSE, TEXT("CreateNetworkingEntryPropertySheet -- Invalid Parameter passed."));
goto exit;
}
//
// Fill in the property page structures
//
for (int i = 0; i < 3; i++)
{
psp[i].dwSize = sizeof(psp[0]);
psp[i].dwFlags = PSP_HASHELP;
psp[i].hInstance = hInstance;
psp[i].lParam = lParam;
}
psp[0].pszTemplate = MAKEINTRESOURCE(IDD_GENERAL);
psp[1].pszTemplate = MAKEINTRESOURCE(IDD_TCPIP_SETTINGS);
psp[2].pszTemplate = MAKEINTRESOURCE(IDD_SECURITY);
psp[0].pfnDlgProc = GeneralPropSheetProc;
psp[1].pfnDlgProc = TcpIpPropSheetProc;
psp[2].pfnDlgProc = SecurityPropSheetProc;
//
// Load the caption
//
uTitleStringId = bUseVpnTitle ? BASE_VPN_ENTRY_TITLE : BASE_DUN_ENTRY_TITLE;
if (bEdit)
{
uTitleStringId = uTitleStringId + EDIT_INCREMENT;
}
else
{
uTitleStringId = uTitleStringId + NEW_INCREMENT;
}
pszCaption = CmLoadString(hInstance, uTitleStringId);
if (NULL == pszCaption)
{
CMASSERTMSG(FALSE, TEXT("CreateNetworkingEntryPropertySheet -- CmLoadString failed trying to load the prop sheet title."));
goto exit;
}
//
// Fill in the property sheet header
//
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_PROPSHEETPAGE | PSH_NOAPPLYNOW | PSH_HASHELP | PSH_NOCONTEXTHELP;
psh.hwndParent = hWizard;
psh.pszCaption = pszCaption;
psh.nPages = sizeof(psp) / sizeof(PROPSHEETPAGE);
psh.ppsp = (LPCPROPSHEETPAGE) &psp[0];
//
// Launch the property sheet
//
iReturn = PropertySheet(&psh);
if (-1 == iReturn)
{
CMTRACE1(TEXT("CreateNetworkingEntryPropertySheet -- PropertySheet called failed, GLE %d"), GetLastError());
}
exit:
CmFree(pszCaption);
return iReturn;
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessDunEntriesAdd
//
// Synopsis: This function is called when the Add button on the DUN entries
// page is pressed. It's job is to create a new CDunSetting
// structure and a new ListBox record and then launch the networking
// entries property page with this newly created DUN entry. If the
// user hits OK on the property sheet then this newly created entry
// is added to the DUN entry linked list. If the user hits cancel
// the entry is freed and never added to the list.
//
// Arguments: HINSTANCE hInstance - instance handle to load resources
// HWND hDlg - window handle of the DUN entries wizard page
// UINT uListCtrlId - control ID of the list containing the DUN entries
// ListBxStruct** pHeadDns - head of the dun entry list
// ListBxStruct** pTailDns - tail of the dun entry list
// BOOL bCreateTunnelEntry - whether we are adding a tunnel entry or not
// LPCTSTR pszLongServiceName - the long service name of the profile
// LPCTSTR pszCmsFile - CMS file to get the default/VPN DUN entry names from
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void OnProcessDunEntriesAdd(HINSTANCE hInstance, HWND hDlg, UINT uListCtrlId, ListBxStruct** pHeadDns, ListBxStruct** pTailDns,
BOOL bCreateTunnelEntry, LPCTSTR pszLongServiceName, LPCTSTR pszCmsFile)
{
//
// Check the input params, make sure that *pHeadDns / *pTailDns are both NULL or both non-NULL
//
if (hInstance && hDlg && pHeadDns && pTailDns && (FALSE == ((NULL == *pHeadDns) ^ (NULL == *pTailDns))))
{
//
// We want to create an empty ListBxStruct and an new CDunSetting. This keeps all of the initialization
// logic in the CDunSetting constructor and keeps the dialog procedures very simple.
//
ListBxStruct* pLinkedListItem = (ListBxStruct*)CmMalloc(sizeof(ListBxStruct));
CDunSetting* pDunSetting = new CDunSetting(bCreateTunnelEntry);
INT_PTR iPropSheetReturnValue = -1;
if ((NULL == pDunSetting) || (NULL == pLinkedListItem))
{
CMASSERTMSG(FALSE, TEXT("OnProcessDunEntriesAdd -- CmMalloc and/or new failed."));
CmFree(pDunSetting);
CmFree(pLinkedListItem);
return;
}
//
// Now call the property sheet
//
BOOL bExitLoop = FALSE;
do
{
pLinkedListItem->ListBxData = (void*)pDunSetting;
iPropSheetReturnValue = CreateNetworkingEntryPropertySheet(hInstance, hDlg, (LPARAM)pLinkedListItem, FALSE, pDunSetting->bTunnelDunSetting); // bEdit == FALSE
if (IDOK == iPropSheetReturnValue)
{
//
// Search the list to make sure that the user didn't give us the name of an existing
// DUN entry. If they did, then we should prompt them for overwrite.
//
ListBxStruct* pCurrent = *pHeadDns;
while (pCurrent)
{
if (0 == lstrcmpi(pCurrent->szName, pLinkedListItem->szName))
{
//
// Then we have a dup, lets prompt the user
//
LPTSTR pszMsg = CmFmtMsg(hInstance, IDS_DUN_NAME_EXISTS, pLinkedListItem->szName);
//
// Make sure to blank out the name. Two things can happen here. Either, the name
// wasn't what the user wanted and they want to change it. In that case, we blank the
// name so that when the dialog comes back up to edit, we won't gray out the name control
// as we normally do for an edit. Since the name was invalid this is an additional clue
// to the user as to what was wrong. If the name was valid and the user means to do a rename,
// then we are going to free pLinkedListItem anyway and blanking the name means nothing. However,
// if we fail to allocate pszMsg, then blanking the name will at least allow the dialog to come back
// up with a edittable name and the user may be able to fix the problem ... unlikely
// if mem allocs are failing but better than leaving the user truly hosed.
//
pLinkedListItem->szName[0] = TEXT('\0');
if (pszMsg)
{
int iResult = MessageBox(hDlg, pszMsg, g_szAppTitle, MB_YESNO);
CmFree(pszMsg);
//
// If the user said yes, lets replace the existing entry and get out of here, otherwise
// we want to loop again.
//
if (IDYES == iResult)
{
CDunSetting* pOldDunSetting = (CDunSetting*)pCurrent->ListBxData;
delete pOldDunSetting;
pCurrent->ListBxData = pDunSetting;
CmFree(pLinkedListItem);
RefreshDnsList(hInstance, hDlg, uListCtrlId, *pHeadDns, pszLongServiceName, pszCmsFile, pCurrent->szName);
bExitLoop = TRUE;
}
break;
}
}
pCurrent = pCurrent->next;
}
//
// If we didn't find a duplicate, then add the item to the list as usual,
// making sure that pLinkedListItem->next is NULL so that the list is terminated.
//
if (NULL == pCurrent)
{
pLinkedListItem->next = NULL; // make sure our list is terminated
if (*pHeadDns)
{
(*pTailDns)->next = pLinkedListItem;
}
else
{
*pHeadDns = pLinkedListItem;
}
*pTailDns = pLinkedListItem;
RefreshDnsList(hInstance, hDlg, uListCtrlId, *pHeadDns, pszLongServiceName, pszCmsFile, pLinkedListItem->szName);
bExitLoop = TRUE;
}
}
else
{
bExitLoop = TRUE;
CmFree(pLinkedListItem);
delete pDunSetting;
}
} while (!bExitLoop);
}
else
{
CMASSERTMSG(FALSE, TEXT("OnProcessDunEntriesAdd -- Invalid parameter passed."));
}
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessDunEntriesEdit
//
// Synopsis: This function is called when the Edit button on the DUN entries
// page is pressed. It's job is to find the ListBox and CDunSetting
// structures for the item currently selected in the listbox and then
// launch the networking entries property page with this DUN entry.
// The property sheet itself takes care of only changing the Dun Entry
// if Okay is pressed. Canceling should leave the entry unchanged.
//
// Arguments: HINSTANCE hInstance - instance handle to load resources
// HWND hDlg - window handle of the DUN entries wizard page
// UINT uListCtrlId - control ID of the list containing the DUN entries
// ListBxStruct** pHeadDns - head of the dun entry list
// ListBxStruct** pTailDns - tail of the dun entry list
// LPCTSTR pszLongServiceName - the long service name of the profile
// LPCTSTR pszCmsFile - CMS file to get the default/VPN DUN entry names from
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void OnProcessDunEntriesEdit(HINSTANCE hInstance, HWND hDlg, UINT uListCtrlId, ListBxStruct** pHeadDns,
ListBxStruct** pTailDns, LPCTSTR pszLongServiceName, LPCTSTR pszCmsFile)
{
LPTSTR pszTunnelDunDisplayString = NULL;
LPTSTR pszDefaultDunDisplayString = NULL;
TCHAR szTunnelDunName[MAX_PATH+1] = TEXT("");
TCHAR szDefaultDunName[MAX_PATH+1] = TEXT("");
LPTSTR pszNameOfItemToEdit = NULL;
//
// Check the input params, make sure that *pHeadDns / *pTailDns are both NULL or both non-NULL
//
if (hInstance && hDlg && pHeadDns && pTailDns && (FALSE == ((NULL == *pHeadDns) ^ (NULL == *pTailDns))))
{
INT_PTR iPropSheetReturnValue = -1;
TCHAR szNameOfItemToEdit[MAX_PATH+1];
ListBxStruct* pItemToEdit = NULL;
//
// Lets get the current selection from the listbox
//
INT_PTR nResult = SendDlgItemMessage(hDlg, uListCtrlId, LB_GETCURSEL, 0, (LPARAM)0);
if (LB_ERR == nResult)
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_NOSELECTION, MB_OK));
}
else
{
if (LB_ERR != SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETTEXT, (WPARAM)nResult, (LPARAM)szNameOfItemToEdit))
{
//
// Get the name of the Tunnel Dun setting
//
MYVERIFY(0 != GetTunnelDunSettingName(pszCmsFile, pszLongServiceName, szTunnelDunName, CELEMS(szTunnelDunName)));
//
// Get the name of the default Dun setting
//
MYVERIFY(0 != GetDefaultDunSettingName(pszCmsFile, pszLongServiceName, szDefaultDunName, CELEMS(szDefaultDunName)));
//
// If we have the default DUN entry text or the default VPN entry text then we want
// to use the real item names for these instead of the text we inserted for
// the user to read.
//
pszTunnelDunDisplayString = CmFmtMsg(hInstance, IDS_DEFAULT_FMT_STR, szTunnelDunName);
pszDefaultDunDisplayString = CmFmtMsg(hInstance, IDS_DEFAULT_FMT_STR, szDefaultDunName);
MYDBGASSERT(pszTunnelDunDisplayString && pszDefaultDunDisplayString);
if (pszTunnelDunDisplayString && pszDefaultDunDisplayString)
{
if (0 == lstrcmpi(pszTunnelDunDisplayString, szNameOfItemToEdit))
{
pszNameOfItemToEdit = szTunnelDunName;
}
else if (0 == lstrcmpi(pszDefaultDunDisplayString, szNameOfItemToEdit))
{
pszNameOfItemToEdit = szDefaultDunName;
}
else
{
pszNameOfItemToEdit = szNameOfItemToEdit;
}
//
// Now find the entry in the list
//
if (FindListItemByName(pszNameOfItemToEdit, *pHeadDns, &pItemToEdit))
{
//
// Finally call the property sheet
//
CDunSetting* pDunSetting = ((CDunSetting*)(pItemToEdit->ListBxData));
BOOL bTunnelSetting = FALSE;
if (pDunSetting)
{
bTunnelSetting = pDunSetting->bTunnelDunSetting;
}
iPropSheetReturnValue = CreateNetworkingEntryPropertySheet(hInstance, hDlg, (LPARAM)pItemToEdit, TRUE, bTunnelSetting); // bEdit == TRUE
if (IDOK == iPropSheetReturnValue)
{
RefreshDnsList(hInstance, hDlg, uListCtrlId, *pHeadDns, pszLongServiceName, pszCmsFile, pItemToEdit->szName);
}
}
else
{
CMASSERTMSG(FALSE, TEXT("OnProcessDunEntriesEdit -- FindListItemByName couldn't find the item in the list."));
}
}
}
else
{
CMASSERTMSG(FALSE, TEXT("OnProcessDunEntriesEdit -- LB_GETTEXT returned an error."));
}
}
}
else
{
CMASSERTMSG(FALSE, TEXT("OnProcessDunEntriesEdit -- Invalid parameter passed."));
}
CmFree(pszDefaultDunDisplayString);
CmFree(pszTunnelDunDisplayString);
}
//+----------------------------------------------------------------------------
//
// Function: OnProcessDunEntriesDelete
//
// Synopsis: This function is called when the Delete button on the DUN entries
// page is pressed. It's job is to find the ListBox and CDunSetting
// structures for the item currently selected in the listbox and then
// remove this item from the DUN entries linked list.
//
// Arguments: HINSTANCE hInstance - instance handle to load resources
// HWND hDlg - window handle of the DUN entries wizard page
// UINT uListCtrlId - control ID of the list containing the DUN entries
// ListBxStruct** pHeadDns - head of the dun entry list
// ListBxStruct** pTailDns - tail of the dun entry list
// LPCTSTR pszLongServiceName - the long service name of the profile
// LPCTSTR pszCmsFile - CMS file to get the default/VPN DUN entry names from
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void OnProcessDunEntriesDelete(HINSTANCE hInstance, HWND hDlg, UINT uListCtrlId, ListBxStruct** pHeadDns,
ListBxStruct** pTailDns, LPCTSTR pszLongServiceName, LPCTSTR pszCmsFile)
{
//
// Check the input params, make sure that *pHeadDns / *pTailDns are both NULL or both non-NULL
//
if (hInstance && hDlg && pHeadDns && pTailDns && (FALSE == ((NULL == *pHeadDns) ^ (NULL == *pTailDns))))
{
TCHAR szNameOfItemToDelete[MAX_PATH+1];
//
// Lets get the current selection from the listbox
//
INT_PTR nResult = SendDlgItemMessage(hDlg, uListCtrlId, LB_GETCURSEL, 0, (LPARAM)0);
if (LB_ERR == nResult)
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_NOSELECTION, MB_OK));
}
else
{
if (LB_ERR != SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETTEXT, (WPARAM)nResult, (LPARAM)szNameOfItemToDelete))
{
//
// Now find the entry in the list
//
ListBxStruct* pCurrent = *pHeadDns;
ListBxStruct* pFollower = NULL;
while (pCurrent)
{
if (0 == lstrcmpi(szNameOfItemToDelete, pCurrent->szName))
{
//
// We found the item to delete
//
if (pFollower)
{
pFollower->next = pCurrent->next;
CDunSetting* pDunSetting = (CDunSetting*)pCurrent->ListBxData;
CmFree(pDunSetting);
CmFree(pCurrent);
//
// We want to continue to the end of the list so that
// we can set the tail pointer appropriately. Thus
// leave pFollower on the item it was on and update
// pCurrent to the next item in the list, if it is NULL
// then we will stop here.
//
pCurrent = pFollower->next;
}
else
{
//
// It is the first item in the list
//
*pHeadDns = (*pHeadDns)->next;
CDunSetting* pDunSetting = (CDunSetting*)pCurrent->ListBxData;
CmFree(pDunSetting);
CmFree(pCurrent);
//
// We want to go to the end of the list to find the tail pointer
// so reset pCurrent to the beginning of the list.
//
pCurrent = *pHeadDns;
}
//
// Don't forget to delete it from the CMS file itself
//
EraseNetworkingSections(szNameOfItemToDelete, pszCmsFile);
//
// Refresh the Dns list
//
RefreshDnsList(hInstance, hDlg, uListCtrlId, *pHeadDns, pszLongServiceName, pszCmsFile, NULL);
}
else
{
pFollower = pCurrent;
pCurrent = pCurrent->next;
}
}
//
// Reset the tail pointer to the last item in the list
//
*pTailDns = pFollower;
}
}
}
else
{
CMASSERTMSG(FALSE, TEXT("OnProcessDunEntriesDelete -- Invalid parameter passed."));
}
}
//+----------------------------------------------------------------------------
//
// Function: EnableDisableIpAddressControls
//
// Synopsis: This function enables or disables the IP address controls for
// the static IP address and for the Wins and DNS server addresses
// depending on the state of the enable/disable radio buttons.
//
// Arguments: HWND hDlg - window handle of the TCP/IP settings dialog
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void EnableDisableIpAddressControls(HWND hDlg)
{
//
// Next Enable/Disable the Wins and DNS address controls
//
BOOL bCheckedState = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_RADIO2));
EnableWindow(GetDlgItem(hDlg, IDC_PRIMARY_DNS), bCheckedState);
EnableWindow(GetDlgItem(hDlg, IDC_LABEL_DNS), bCheckedState);
EnableWindow(GetDlgItem(hDlg, IDC_SECONDARY_DNS), bCheckedState);
EnableWindow(GetDlgItem(hDlg, IDC_LABEL_DNS2), bCheckedState);
EnableWindow(GetDlgItem(hDlg, IDC_PRIMARY_WINS), bCheckedState);
EnableWindow(GetDlgItem(hDlg, IDC_LABEL_WINS), bCheckedState);
EnableWindow(GetDlgItem(hDlg, IDC_SECONDARY_WINS), bCheckedState);
EnableWindow(GetDlgItem(hDlg, IDC_LABEL_WINS2), bCheckedState);
}
//+----------------------------------------------------------------------------
//
// Function: TcpIpPropSheetProc
//
// Synopsis: This function processes messages for TCP/IP Settings property sheet.
//
// Arguments: HWND hDlg - window handle to the dialog
// UINT message - the current message to process
// WPARAM wParam - wParam see individual message type for details
// LPARAM lParam - lParam see individual message type for details
//
// Returns: INT_PTR - TRUE if the message was completely handled
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
INT_PTR APIENTRY TcpIpPropSheetProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
NMHDR* pnmHeader = (NMHDR*)lParam;
static DWORD_PTR HelpId = 0;
static ListBxList* pListEntry = NULL;
static CDunSetting* pDunSetting = NULL;
if (ProcessHelp(hDlg, message, wParam, lParam, HelpId)) return TRUE;
switch (message)
{
case WM_INITDIALOG:
if (lParam)
{
PROPSHEETPAGE* pPropSheetPage = (PROPSHEETPAGE*)lParam;
if (pPropSheetPage->lParam)
{
pListEntry = (ListBxList*)pPropSheetPage->lParam;
pDunSetting = (CDunSetting*)pListEntry->ListBxData;
UINT uCrtlToSet;
if (pListEntry && pDunSetting)
{
//
// Setup the help ID appropriately
//
HelpId = ((pDunSetting->bTunnelDunSetting) ? IDH_VENTRY : IDH_DENTRY);
//
// Init the WINS and DNS IP address controls and the radio buttons specifying
// whether the user chose to give us addresses or not.
//
if (pDunSetting->dwPrimaryDns || pDunSetting->dwSecondaryDns || pDunSetting->dwPrimaryWins || pDunSetting->dwSecondaryWins)
{
uCrtlToSet = IDC_RADIO2;
SendDlgItemMessage(hDlg, IDC_PRIMARY_DNS, IPM_SETADDRESS, (WPARAM)0, (LPARAM)(pDunSetting->dwPrimaryDns));
SendDlgItemMessage(hDlg, IDC_SECONDARY_DNS, IPM_SETADDRESS, (WPARAM)0, (LPARAM)(pDunSetting->dwSecondaryDns));
SendDlgItemMessage(hDlg, IDC_PRIMARY_WINS, IPM_SETADDRESS, (WPARAM)0, (LPARAM)(pDunSetting->dwPrimaryWins));
SendDlgItemMessage(hDlg, IDC_SECONDARY_WINS, IPM_SETADDRESS, (WPARAM)0, (LPARAM)(pDunSetting->dwSecondaryWins));
}
else
{
uCrtlToSet = IDC_RADIO1;
SendDlgItemMessage(hDlg, IDC_PRIMARY_DNS, IPM_CLEARADDRESS, (WPARAM)0, (LPARAM)0);
SendDlgItemMessage(hDlg, IDC_SECONDARY_DNS, IPM_CLEARADDRESS, (WPARAM)0, (LPARAM)0);
SendDlgItemMessage(hDlg, IDC_PRIMARY_WINS, IPM_CLEARADDRESS, (WPARAM)0, (LPARAM)0);
SendDlgItemMessage(hDlg, IDC_SECONDARY_WINS, IPM_CLEARADDRESS, (WPARAM)0, (LPARAM)0);
}
MYVERIFY(0 != CheckRadioButton(hDlg, IDC_RADIO1, IDC_RADIO2, uCrtlToSet));
//
// Finally set the checkboxes for IP header compression and whether to use
// the remote gateway or not.
//
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_CHECK1, pDunSetting->bGatewayOnRemote));
MYVERIFY(0 != CheckDlgButton(hDlg, IDC_CHECK2, pDunSetting->bIpHeaderCompression));
EnableDisableIpAddressControls(hDlg);
}
else
{
CMASSERTMSG(FALSE, TEXT("TcpIpPropSheetProc -- pListEntry or pDunSetting are NULL"));
}
}
else
{
pListEntry = NULL;
pDunSetting = NULL;
CMASSERTMSG(FALSE, TEXT("TcpIpPropSheetProc -- NULL lParam passed to InitDialog. Dialog controls will all be set to off."));
}
}
else
{
pListEntry = NULL;
pDunSetting = NULL;
CMASSERTMSG(FALSE, TEXT("TcpIpPropSheetProc -- NULL PropSheetPage pointer passed for lParam."));
}
break;
case WM_NOTIFY:
if (NULL == pnmHeader)
{
return FALSE;
}
switch (pnmHeader->code)
{
case PSN_APPLY:
if (pListEntry && pDunSetting)
{
//
// Okay, lets read in the settings and save them to the passed
// in CDunSetting pointer.
//
if (IsDlgButtonChecked(hDlg, IDC_RADIO2))
{
SendDlgItemMessage(hDlg, IDC_PRIMARY_DNS, IPM_GETADDRESS, (WPARAM)0, (LPARAM)&(pDunSetting->dwPrimaryDns));
SendDlgItemMessage(hDlg, IDC_SECONDARY_DNS, IPM_GETADDRESS, (WPARAM)0, (LPARAM)&(pDunSetting->dwSecondaryDns));
SendDlgItemMessage(hDlg, IDC_PRIMARY_WINS, IPM_GETADDRESS, (WPARAM)0, (LPARAM)&(pDunSetting->dwPrimaryWins));
SendDlgItemMessage(hDlg, IDC_SECONDARY_WINS, IPM_GETADDRESS, (WPARAM)0, (LPARAM)&(pDunSetting->dwSecondaryWins));
}
else
{
pDunSetting->dwPrimaryDns = 0;
pDunSetting->dwSecondaryDns = 0;
pDunSetting->dwPrimaryWins = 0;
pDunSetting->dwSecondaryWins = 0;
}
pDunSetting->bGatewayOnRemote = IsDlgButtonChecked(hDlg, IDC_CHECK1);
pDunSetting->bIpHeaderCompression = IsDlgButtonChecked(hDlg, IDC_CHECK2);
}
break;
default:
break;
}
break;
case WM_COMMAND:
switch (LOWORD(wParam))
{
case IDC_RADIO1:
case IDC_RADIO2:
EnableDisableIpAddressControls(hDlg);
break;
default:
break;
}
break;
default:
return FALSE;
}
return FALSE;
} //lint !e715 we don't reference lParam
//+----------------------------------------------------------------------------
//
// Function: RefreshDnsList
//
// Synopsis: This function clears the contents of the listbox specified by
// hDlg and uCrtlId. Then it adds each of the items in the DUN
// entries linked list specified by pHead to the listbox. The
// passed in CMS file is used to figure out which entries to special
// with the default entry and VPN entry text.
//
// Arguments: HINSTANCE hInstance - instance handle for loading resources
// HWND hDlg - window handle for the DUN entries dialog
// UINT uCtrlId - control ID of the Listbox to write the entries to
// ListBxList * pHead - head of the linked list of DUN entries
// LPCTSTR pszLongServiceName - long service name of the profile
// LPCTSTR pszCmsFile - CMS file to get the DUN and TunnelDUN entries from
// LPTSTR pszItemToSelect - Item in the list to select after the refresh,
// NULL chooses the first in the list
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void RefreshDnsList(HINSTANCE hInstance, HWND hDlg, UINT uCtrlId, ListBxList * pHead,
LPCTSTR pszLongServiceName, LPCTSTR pszCmsFile, LPTSTR pszItemToSelect)
{
if (hDlg && pHead)
{
TCHAR szTunnelSettingName[MAX_PATH+1] = TEXT("");
TCHAR szDefaultSettingName[MAX_PATH+1] = TEXT("");
//
// Get the name of the Tunnel Dun setting
//
MYVERIFY(0 != GetTunnelDunSettingName(pszCmsFile, pszLongServiceName, szTunnelSettingName, CELEMS(szTunnelSettingName)));
//
// Get the name of the default Dun setting
//
MYVERIFY(0 != GetDefaultDunSettingName(pszCmsFile, pszLongServiceName, szDefaultSettingName, CELEMS(szDefaultSettingName)));
//
// Reset the listbox contents
//
SendDlgItemMessage(hDlg, uCtrlId, LB_RESETCONTENT, 0, (LPARAM)0); //lint !e534 LB_RESETCONTENT doesn't return anything
//
// Now loop through the Network settings, adding them to the listbox
//
ListBxList * pCurrent = pHead;
LPTSTR pszDisplayString;
BOOL bFreeString;
BOOL bAddDefaultFmtStr = TRUE;
while(pCurrent)
{
if ((0 == lstrcmpi(szTunnelSettingName, pCurrent->szName)) && bAddDefaultFmtStr)
{
pszDisplayString = CmFmtMsg(hInstance, IDS_DEFAULT_FMT_STR, pCurrent->szName);
MYDBGASSERT(pszDisplayString);
bFreeString = TRUE;
bAddDefaultFmtStr = FALSE;
}
else if ((0 == lstrcmpi(szDefaultSettingName, pCurrent->szName)) && bAddDefaultFmtStr)
{
pszDisplayString = CmFmtMsg(hInstance, IDS_DEFAULT_FMT_STR, pCurrent->szName);
MYDBGASSERT(pszDisplayString);
bFreeString = TRUE;
bAddDefaultFmtStr = FALSE;
}
else
{
pszDisplayString = pCurrent->szName;
bFreeString = FALSE;
}
if (pszDisplayString)
{
MYVERIFY(LB_ERR != SendDlgItemMessage(hDlg, uCtrlId, LB_ADDSTRING, 0, (LPARAM)pszDisplayString));
if (bFreeString)
{
CmFree(pszDisplayString);
}
}
pCurrent = pCurrent->next;
}
//
// Now Select the requested item in the list. If the requested name is NULL, just select the
// first item in the list.
//
LRESULT lResult = 0;
if (pszItemToSelect)
{
LPTSTR pszSearchString;
if (0 == lstrcmpi(szTunnelSettingName, pszItemToSelect))
{
pszSearchString = CmFmtMsg(hInstance, IDS_DEFAULT_FMT_STR, pszItemToSelect);
}
else if (0 == lstrcmpi(szDefaultSettingName, pszItemToSelect))
{
pszSearchString = CmFmtMsg(hInstance, IDS_DEFAULT_FMT_STR, pszItemToSelect);
}
else
{
pszSearchString = CmStrCpyAlloc(pszItemToSelect);
}
if (pszSearchString)
{
lResult = SendDlgItemMessage(hDlg, uCtrlId, LB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pszSearchString);
if (LB_ERR == lResult)
{
lResult = 0;
}
CmFree(pszSearchString);
}
}
SendDlgItemMessage(hDlg, uCtrlId, LB_SETCURSEL, (WPARAM)lResult, (LPARAM)0); // don't assert we may not have any items
EnableDisableDunEntryButtons(hInstance, hDlg, pszCmsFile, pszLongServiceName);
}
}
//+----------------------------------------------------------------------------
//
// Function: SelectAppropriateEAP
//
// Synopsis: This functions walks through the list of EAPData structures held
// by the item data pointers of the EAP names in the combobox specified
// by hDlg and uCtrlId. For each EAPData structure it compares
// the dwCustomAuthKey field with that of the pDunSetting->dwCustomAuthKey.
// When it finds a match it selects that item in the list. Note there
// is a special case for pDunSetting->dwCustomAuthKey == 0, in that
// since the dun setting doesn't specify and EAP we pick the first
// one in the list. If the EAP specified in pDunSetting isn't found
// then nothing is selected. However, this should never happen because
// if the profile specifies an EAP type not found on the machine it will
// add a special entry for it.
//
// Arguments: HWND hDlg - window handle of the win2k security dialog
// UINT uCtrlId - control ID of the combo containing the EAP types
// CDunSetting* pDunSetting - dun setting for which to locate the EAP
// for, contains the dwCustomAuthKey to try
// to match.
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void SelectAppropriateEAP(HWND hDlg, UINT uCtrlId, CDunSetting* pDunSetting)
{
MYDBGASSERT(hDlg && uCtrlId && pDunSetting);
if (hDlg && uCtrlId && pDunSetting)
{
WPARAM wpIndex = 0;
INT_PTR nResult;
BOOL bEapSelected = FALSE;
if (0 == pDunSetting->dwCustomAuthKey)
{
//
// Select the first EAP in the list
//
SendDlgItemMessage(hDlg, uCtrlId, CB_SETCURSEL, (WPARAM)0, (LPARAM)0);
}
else
{
do
{
nResult = SendDlgItemMessage(hDlg, uCtrlId, CB_GETITEMDATA, wpIndex, (LPARAM)0);
if (CB_ERR != nResult)
{
EAPData* pEapData = (EAPData*)nResult;
if (pEapData && (pEapData->dwCustomAuthKey == pDunSetting->dwCustomAuthKey))
{
SendDlgItemMessage(hDlg, uCtrlId, CB_SETCURSEL, wpIndex, (LPARAM)0);
bEapSelected = TRUE;
break;
}
wpIndex++;
}
} while (CB_ERR != nResult);
}
}
}
//+----------------------------------------------------------------------------
//
// Function: FreeEapData
//
// Synopsis: This functions walks through the list of EAPData structures held
// by the item data pointers of the EAP names in the combobox specified
// by hDlg and uCtrlId. For each EAPData structure it releases the
// memory held by the EAPData structure, including the pszFriendlyName,
// the config dll path, and any custom auth data blobs that exist.
//
// Arguments: HWND hDlg - window handle of the win2k security dialog
// UINT uCtrlId - control ID of the combo containing the EAP types
//
// Returns: Nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void FreeEapData(HWND hDlg, UINT uCtrlId)
{
MYDBGASSERT(hDlg && uCtrlId);
if (hDlg && uCtrlId)
{
WPARAM wpIndex = 0;
INT_PTR nResult;
EAPData* pEapData;
do
{
nResult = SendDlgItemMessage(hDlg, uCtrlId, CB_GETITEMDATA, wpIndex, (LPARAM)0);
if (CB_ERR != nResult)
{
pEapData = (EAPData*)nResult;
if (pEapData)
{
CmFree(pEapData->pszFriendlyName);
CmFree(pEapData->pszConfigDllPath);
CmFree(pEapData->pCustomAuthData);
CmFree(pEapData);
}
wpIndex++;
}
} while (CB_ERR != nResult);
}
}
//+----------------------------------------------------------------------------
//
// Function: HrQueryRegStringWithAlloc
//
// Synopsis: This functions retrieves the string value specified by hKey and
// pszValueName. Note that the function queries the value to find
// out how much memory is needed to retrieve the data and then
// allocates the correct amount and retrieves the data itself. The
// returned buffer must be freed by the caller.
//
// Arguments: HKEY hKey - open handle to the regkey to get the value from
// LPCTSTR pszValueName - name of the value to retrieve data for
// TCHAR** ppszReturnString - pointer to hold the allocated string
// data retrieved from the registry value.
//
// Returns: HRESULT - standard COM style return codes
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
HRESULT HrQueryRegStringWithAlloc(HKEY hKey, LPCTSTR pszValueName, TCHAR** ppszReturnString)
{
if ((NULL == hKey) || (NULL == pszValueName) || (NULL == ppszReturnString) || (TEXT('\0') == pszValueName[0]))
{
CMASSERTMSG(FALSE, TEXT("HrQueryRegStringWithAlloc -- invalid parameter"));
return E_INVALIDARG;
}
HRESULT hr = S_OK;
DWORD dwType;
DWORD dwSize = 2;
TCHAR szTwo[2];
LPTSTR pszTemp = NULL;
LONG lReturn = RegQueryValueEx(hKey, pszValueName, NULL, &dwType, (LPBYTE)szTwo, &dwSize);
if (ERROR_MORE_DATA == lReturn)
{
*ppszReturnString = (LPTSTR)CmMalloc(dwSize);
if (*ppszReturnString)
{
lReturn = RegQueryValueEx(hKey, pszValueName, NULL, &dwType, (LPBYTE)*ppszReturnString, &dwSize);
hr = HRESULT_FROM_WIN32(lReturn);
if (SUCCEEDED(hr))
{
if (REG_EXPAND_SZ == dwType)
{
DWORD dwExpandedSize = sizeof(TCHAR)*(ExpandEnvironmentStrings(*ppszReturnString, NULL, 0));
if (dwExpandedSize && (dwSize != dwExpandedSize))
{
pszTemp = *ppszReturnString;
*ppszReturnString = (LPTSTR)CmMalloc(dwExpandedSize);
if (*ppszReturnString)
{
ExpandEnvironmentStrings(pszTemp, *ppszReturnString, dwExpandedSize);
}
else
{
CMASSERTMSG(FALSE, TEXT("HrQueryRegStringWithAlloc -- CmMalloc returned a NULL pointer."));
hr = E_OUTOFMEMORY;
}
CmFree(pszTemp);
}
}
}
}
else
{
CMASSERTMSG(FALSE, TEXT("HrQueryRegStringWithAlloc -- CmMalloc returned a NULL pointer."));
hr = E_OUTOFMEMORY;
}
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Function: ComboBox_GetPsz
//
// Synopsis: This function automatically allocates and returns the string with
// the given index from the given combobox. Happily stolen from Rasdlg.
//
// Arguments: HWND hDlg - window handle to the combobox
//
// Returns: Nothing
//
// History: quintinb Created header 04/02/2002
//
//+----------------------------------------------------------------------------
TCHAR* ComboBox_GetPsz(IN HWND hwnd, IN INT nIndex)
//
// Returns heap block containing the text contents of the 'nIndex'th item
// of combo box 'hwnd' or NULL. It is caller's responsibility to Free the
// returned string.
//
{
INT cch;
TCHAR* psz;
cch = ComboBox_GetLBTextLen( hwnd, nIndex );
if (cch < 0)
{
return NULL;
}
psz = (TCHAR*)CmMalloc( (cch + 1) * sizeof(TCHAR) );
if (psz)
{
*psz = TEXT('\0');
ComboBox_GetLBText( hwnd, nIndex, psz );
}
return psz;
}
//+----------------------------------------------------------------------------
//
// Function: ComboBox_AutoSizeDroppedWidth
//
// Synopsis: This function automatically sizes the combobox dropdown based on
// the strings already in the combobox. Happily stolen from Rasdlg.
//
// Arguments: HWND hDlg - window handle to the combobox
//
// Returns: Nothing
//
// History: quintinb Created header 04/02/2002
//
//+----------------------------------------------------------------------------
VOID ComboBox_AutoSizeDroppedWidth(IN HWND hwndLb)
// Set the width of the drop-down list 'hwndLb' to the width of the
// longest item (or the width of the list box if that's wider).
//
{
HDC hdc;
HFONT hfont;
TCHAR* psz;
SIZE size;
DWORD cch;
DWORD dxNew;
DWORD i;
hfont = (HFONT )SendMessage(hwndLb, WM_GETFONT, 0, 0);
if (!hfont)
{
return;
}
hdc = GetDC(hwndLb);
if (!hdc)
{
return;
}
SelectObject(hdc, hfont);
dxNew = 0;
for (i = 0; psz = ComboBox_GetPsz(hwndLb, i); ++i)
{
cch = lstrlen( psz );
if (GetTextExtentPoint32(hdc, psz, cch, &size))
{
if (dxNew < (DWORD )size.cx)
dxNew = (DWORD )size.cx;
}
CmFree(psz);
}
ReleaseDC(hwndLb, hdc);
//
// Allow for the spacing on left and right added by the control.
//
dxNew += 6;
// Figure out if the vertical scrollbar will be displayed and, if so,
// allow for it's width.
//
RECT rectD;
RECT rectU;
DWORD dyItem;
DWORD cItemsInDrop;
DWORD cItemsInList;
GetWindowRect(hwndLb, &rectU);
SendMessage(hwndLb, CB_GETDROPPEDCONTROLRECT, 0, (LPARAM )&rectD);
dyItem = (DWORD)SendMessage(hwndLb, CB_GETITEMHEIGHT, 0, 0);
cItemsInDrop = (rectD.bottom - rectU.bottom) / dyItem;
cItemsInList = ComboBox_GetCount(hwndLb);
if (cItemsInDrop < cItemsInList)
{
dxNew += GetSystemMetrics(SM_CXVSCROLL);
}
SendMessage(hwndLb, CB_SETDROPPEDWIDTH, dxNew, 0);
}
//+----------------------------------------------------------------------------
//
// Function: ShowEapToUser
//
// Synopsis: This function examines the roles value of the given registry key
// represented by the passed in registry handle and decides whether
// the role tells us to show it to the user or not.
//
// Arguments: HKEY hKeyPackage - handle to the reg key of the EAP package
//
// Returns: BOOL - TRUE shows it to the user, FALSE skips the package
//
// History: quintinb Created 11/12/02
//
//+----------------------------------------------------------------------------
BOOL ShowEapToUser(HKEY hKeyPackage)
{
DWORD dwRolesSupported = 0;
DWORD dwSize = sizeof(dwRolesSupported);
DWORD dwType = REG_DWORD;
DWORD dwReturn = RegQueryValueEx(hKeyPackage, RAS_EAP_VALUENAME_ROLES_SUPPORTED, NULL,
&dwType, (LPBYTE)(&dwRolesSupported), &dwSize);
//
// If we couldn't access the key, assume it is okay to show it to the user. This
// will generally mean the key didn't exist... (which is okay it supports all roles).
//
if (ERROR_SUCCESS == dwReturn)
{
//
// This value is a set of flags that tell what roles the EAP
// supports. Whether the EAP can be used in server (authenticator) or client
// (authenticatee) and whether it is supported for RAS connections (VPN) or
// in PEAP. For our purposes, we only want to show EAP's that can be used by the
// client for EAP and VPN. If the EAP supports all of that show it, otherwise don't.
//
if (0 != dwRolesSupported)
{
if (!(RAS_EAP_ROLE_AUTHENTICATEE & dwRolesSupported))
{
return FALSE;
}
if (RAS_EAP_ROLE_EXCLUDE_IN_EAP & dwRolesSupported)
{
return FALSE;
}
if (RAS_EAP_ROLE_EXCLUDE_IN_VPN & dwRolesSupported)
{
return FALSE;
}
}
}
return TRUE;
}
//+----------------------------------------------------------------------------
//
// Function: HrAddAvailableEAPsToCombo
//
// Synopsis: This functions enumerates the EAP types listed in the registry
// and adds them to the EAP types combo. For each type of EAP the
// dwCustomAuthKey (numerical type of the EAP), the description string,
// the configuration UI dll path, and whether configuration is
// required is recorded in an EAPData structure and stored in the
// item data pointer of the combobox item. The passed in CDunSetting
// structure is used for two purposes. First this function checks to
// make sure that the EAP of the type that is specified in the
// CDunSetting structure is actually installed on the machine. If it
// isn't the user is presented with a warning message and the type is
// added as "EAP Type %d <not installed>". This is a choice in the UI
// but the user is unable to configure it unless they install the EAP.
// Also, if the EAP of the type specified in the CDunSetting is installed
// then the dwCustomAuthData and dwCustomAuthDataSize elements of the
// CDunSetting are copied over. Thus maintains the simplicity of letting
// the user configure any EAP they wish and then only picking up that
// data in the DUN setting when they hit okay. Thus allowing Cancel
// to work as one would expect.
//
// Arguments: HWND hDlg - window handle to the win2k security dialog
// UINT uCtrlId - EAP types combo box ID
// CDunSetting* pDunSetting - DUN setting data that we are currently
// adding/editing
//
// Returns: HRESULT - standard COM style return codes
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
HRESULT HrAddAvailableEAPsToCombo(HWND hDlg, UINT uCtrlId, CDunSetting* pDunSetting)
{
if ((NULL == hDlg) || (0 == uCtrlId) || (NULL == pDunSetting))
{
CMASSERTMSG(FALSE, TEXT("HrAddAvailableEAPsToCombo -- Invalid parameter passed."));
return E_INVALIDARG;
}
HKEY hKey = NULL;
HRESULT hr = S_OK;
LONG lReturn;
LPTSTR pszPath;
BOOL bEapTypeFound = FALSE;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, RAS_EAP_REGISTRY_LOCATION, 0, KEY_READ, &hKey))
{
//
// Now begin enumerating the EAPs
//
TCHAR szSubKeyName[MAX_PATH+1]; // the key names are numbers representing the type of EAP, thus MAX_PATH is probably overkill
DWORD dwIndex = 0;
HKEY hTempKey = NULL;
do
{
lReturn = RegEnumKey(hKey, dwIndex, szSubKeyName, CELEMS(szSubKeyName));
if (ERROR_SUCCESS == lReturn)
{
//
// We potentially have an EAP reg key. Thus lets open a handle to this
// key and see if it has the values we are looking for.
//
if (ERROR_SUCCESS == RegOpenKeyEx(hKey, szSubKeyName, 0, KEY_READ, &hTempKey))
{
//
// Check to see if we need to filter out PEAP and EAP-MsChapV2. That means checking the
// checking the roles value of each EAP package.
//
if (FALSE == ShowEapToUser(hTempKey))
{
RegCloseKey(hTempKey);
dwIndex++; // bump the index
continue;
}
//
// Get the path value, if we don't have a path value then just ignore the entry and move on
//
hr = HrQueryRegStringWithAlloc(hTempKey, RAS_EAP_VALUENAME_PATH, &pszPath);
if (SUCCEEDED(hr))
{
//
// Free the path, we don't really need to keep this value.
//
CmFree(pszPath);
EAPData* pEapData = (EAPData*)CmMalloc(sizeof(EAPData));
if (pEapData)
{
//
// Now get the Friendly name of the EAP to add to the combobox
//
HrQueryRegStringWithAlloc(hTempKey, RAS_EAP_VALUENAME_FRIENDLY_NAME, &(pEapData->pszFriendlyName));
//
// Next check to see if we have configuration UI for this EAP, thus requiring we store the
//
HrQueryRegStringWithAlloc(hTempKey, RAS_EAP_VALUENAME_CONFIGUI, &(pEapData->pszConfigDllPath));
//
// We also need to save the type value
//
pEapData->dwCustomAuthKey = _ttoi(szSubKeyName);
//
// If the pDunSetting has pCustomAuthData and it is the same type as the current EAP we are
// processing then we need to add the copy the EAP blob to the EAPData structure.
//
if (pDunSetting->dwCustomAuthKey == pEapData->dwCustomAuthKey)
{
if (pDunSetting->pCustomAuthData && pDunSetting->dwCustomAuthDataSize)
{
pEapData->pCustomAuthData = (LPBYTE)CmMalloc(pDunSetting->dwCustomAuthDataSize);
if (pEapData->pCustomAuthData)
{
pEapData->dwCustomAuthDataSize = pDunSetting->dwCustomAuthDataSize;
CopyMemory(pEapData->pCustomAuthData, pDunSetting->pCustomAuthData, pEapData->dwCustomAuthDataSize);
}
}
bEapTypeFound = TRUE;
}
//
// Get whether we must require configuration or not
//
DWORD dwSize = sizeof(pEapData->bMustConfig);
DWORD dwType = REG_DWORD;
if (ERROR_SUCCESS != RegQueryValueEx(hTempKey, RAS_EAP_VALUENAME_REQUIRE_CONFIGUI, NULL, &dwType, (LPBYTE)&(pEapData->bMustConfig), &dwSize))
{
pEapData->bMustConfig = FALSE;
}
dwSize = sizeof(pEapData->bSupportsEncryption);
if (ERROR_SUCCESS != RegQueryValueEx(hTempKey, RAS_EAP_VALUENAME_ENCRYPTION, NULL, &dwType, (LPBYTE)&(pEapData->bSupportsEncryption), &dwSize))
{
pEapData->bSupportsEncryption = FALSE;
}
//
// Finally add the EAP to the combobox
//
LPTSTR pszDisplayString = NULL;
TCHAR szDisplayString[MAX_PATH+1];
if (pEapData->bSupportsEncryption)
{
LPTSTR pszSuffix = CmLoadString(g_hInstance, IDS_SUPPORTS_ENCRYPT);
if (pszSuffix)
{
wsprintf(szDisplayString, TEXT("%s %s"), pEapData->pszFriendlyName, pszSuffix);
pszDisplayString = szDisplayString;
CmFree(pszSuffix);
}
}
if (NULL == pszDisplayString)
{
pszDisplayString = pEapData->pszFriendlyName;
}
INT_PTR nResult = SendDlgItemMessage(hDlg, uCtrlId, CB_ADDSTRING, (WPARAM)0, (LPARAM)pszDisplayString);
if (CB_ERR != nResult)
{
SendDlgItemMessage(hDlg, uCtrlId, CB_SETITEMDATA, (WPARAM)nResult, (LPARAM)pEapData);
}
else
{
CMASSERTMSG(FALSE, TEXT("HrAddAvailableEAPsToCombo -- unable to set item data."));
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
else
{
CMASSERTMSG(FALSE, TEXT("HrAddAvailableEAPsToCombo -- CmMalloc returned a NULL pointer."));
hr = E_OUTOFMEMORY;
}
}
else
{
CMTRACE2(TEXT("HrAddAvailableEAPsToCombo -- Unable to find Path value for EAP regkey %s, hr %d"), szSubKeyName, hr);
}
}
else
{
CMTRACE2(TEXT("HrAddAvailableEAPsToCombo -- Unable to Open EAP regkey %s, GLE %d"), szSubKeyName, GetLastError());
}
}
dwIndex++;
} while (ERROR_SUCCESS == lReturn);
if (hTempKey)
{
(VOID)RegCloseKey(hTempKey);
hTempKey = NULL;
}
//
// Auto size the combo box drop down
//
HWND hCombo = GetDlgItem(hDlg, uCtrlId);
if (hCombo)
{
ComboBox_AutoSizeDroppedWidth(hCombo);
}
//
// If the Dun setting contains an EAP that isn't on the system
// we need to prompt the user.
//
if (pDunSetting->dwCustomAuthKey && (FALSE == bEapTypeFound))
{
MYVERIFY(IDOK == ShowMessage(hDlg, IDS_EAP_NOT_FOUND, MB_OK | MB_ICONINFORMATION));
EAPData* pEapData = (EAPData*)CmMalloc(sizeof(EAPData));
if (pEapData)
{
pEapData->pszFriendlyName = CmFmtMsg(g_hInstance, IDS_EAP_NOT_FOUND_TYPE, pDunSetting->dwCustomAuthKey);
pEapData->dwCustomAuthKey = pDunSetting->dwCustomAuthKey;
pEapData->bNotInstalled = TRUE;
INT_PTR nResult = SendDlgItemMessage(hDlg, uCtrlId, CB_ADDSTRING, (WPARAM)0, (LPARAM)(pEapData->pszFriendlyName));
if (CB_ERR != nResult)
{
SendDlgItemMessage(hDlg, uCtrlId, CB_SETITEMDATA, (WPARAM)nResult, (LPARAM)pEapData);
}
else
{
CMASSERTMSG(FALSE, TEXT("HrAddAvailableEAPsToCombo -- CmMalloc returned a NULL pointer."));
hr = HRESULT_FROM_WIN32(GetLastError());
}
}
}
}
else
{
hr = HRESULT_FROM_WIN32(GetLastError());
}
if (hKey)
{
(VOID)RegCloseKey(hKey);
}
return hr;
}
//+----------------------------------------------------------------------------
//
// Function: FreeDnsList
//
// Synopsis: Since the ListBxData in the list box items of the DNS
// list are actually CDunSetting class pointers we must
// properly cast the pointer so that they are destructed
// corretly.
//
// Arguments: ListBxList ** HeadPtr - head of the DUN setting list
//
// Returns: nothing
//
// History: quintinb Created 03/27/00
//
//+----------------------------------------------------------------------------
void FreeDnsList(ListBxList ** pHeadPtr, ListBxList ** pTailPtr)
{
CDunSetting* pDunSetting;
ListBxList* pCurrent = *pHeadPtr;
ListBxList* pTemp;
while (NULL != pCurrent)
{
pTemp = pCurrent;
//
// Free the DunSetting
//
pDunSetting = (CDunSetting*)pCurrent->ListBxData;
delete pDunSetting;
pCurrent = pCurrent->next;
CmFree(pTemp);
}
*pHeadPtr = NULL;
*pTailPtr = NULL;
}
//+----------------------------------------------------------------------------
//
// Function: EnableDisableDunEntryButtons
//
// Synopsis: This function enables or disables the Add and Edit buttons on
// the Dun entries screen. It also enables or disables the delete
// button depending on whether the current selection is a built in
// entry or not.
//
// Arguments: HINSTANCE hInstance - instance handle to load resources with
// HWND hDlg - window handle to the dun entries dialog
// LPCTSTR pszCmsFile - full path to the cms file
// LPCTSTR pszLongServiceName - long service name of the profile
//
// Returns: Nothing
//
// History: quintinb Created 9/11/98
//
//+----------------------------------------------------------------------------
void EnableDisableDunEntryButtons(HINSTANCE hInstance, HWND hDlg, LPCTSTR pszCmsFile, LPCTSTR pszLongServiceName)
{
LRESULT lResult;
BOOL bEnableEdit = FALSE;
BOOL bEnableDelete = FALSE;
lResult = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETCOUNT, 0, 0);
if (LB_ERR != lResult)
{
if (0 == lResult)
{
//
// Zero Items, set focus to the Add Button
//
SetFocus(GetDlgItem(hDlg, IDC_BUTTON1));
}
else
{
//
// Enable the Edit Button because we have at least 1 item.
//
bEnableEdit = TRUE;
//
// Now lets figure out if the delete button should be enabled or not.
// If we have at least one item then we normally want to enable the
// delete button. However, if the current selection is on the VPN
// connection or the default connection then we don't want the user to
// delete these and we will have to disable the delete button (note that
// even if the user hit the delete button on one of these items we wouldn't
// delete it). So, lets get the Cursor selection to see if we need to
// disable the delete button.
//
LRESULT lCurrentIndex = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETCURSEL, 0, 0);
if (LB_ERR == lCurrentIndex)
{
MYVERIFY(LB_ERR != SendDlgItemMessage(hDlg, IDC_LIST1, LB_SETCURSEL, 0, (LPARAM)0));
lCurrentIndex = 0;
}
TCHAR szTunnelDunName[MAX_PATH+1] = TEXT("");
TCHAR szDefaultDunName[MAX_PATH+1] = TEXT("");
//
// Get the name of the Tunnel Dun setting
//
MYVERIFY(0 != GetTunnelDunSettingName(pszCmsFile, pszLongServiceName, szTunnelDunName, CELEMS(szTunnelDunName)));
//
// Get the name of the default Dun setting
//
MYVERIFY(0 != GetDefaultDunSettingName(pszCmsFile, pszLongServiceName, szDefaultDunName, CELEMS(szDefaultDunName)));
//
// If we have the default entry text or the tunnel entry text then we want
// to use the real item names for these instead of the text we inserted for
// the user to read.
//
LPTSTR pszTunnelDunDisplayString = CmFmtMsg(hInstance, IDS_DEFAULT_FMT_STR, szTunnelDunName);
LPTSTR pszDefaultDunDisplayString = CmFmtMsg(hInstance, IDS_DEFAULT_FMT_STR, szDefaultDunName);
LPTSTR pszCurrentSelection = NULL;
MYDBGASSERT(pszTunnelDunDisplayString && pszDefaultDunDisplayString);
if (pszTunnelDunDisplayString && pszDefaultDunDisplayString)
{
lResult = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETTEXTLEN, lCurrentIndex, (LPARAM)0);
if (LB_ERR != lResult)
{
pszCurrentSelection = (LPTSTR)CmMalloc((lResult + 1) * sizeof(TCHAR));
if (pszCurrentSelection)
{
lResult = SendDlgItemMessage(hDlg, IDC_LIST1, LB_GETTEXT, lCurrentIndex, (LPARAM)pszCurrentSelection);
if ((0 != lstrcmpi(pszCurrentSelection, pszTunnelDunDisplayString)) &&
(0 != lstrcmpi(pszCurrentSelection, pszDefaultDunDisplayString)))
{
bEnableDelete = TRUE;
}
}
}
CmFree(pszTunnelDunDisplayString);
CmFree(pszDefaultDunDisplayString);
CmFree(pszCurrentSelection);
}
}
}
HWND hDeleteButton = GetDlgItem(hDlg, IDC_BUTTON3);
HWND hCurrentFocus = GetFocus();
HWND hControl = GetDlgItem(hDlg, IDC_BUTTON2); // Edit button == IDC_BUTTON2
if (hControl) // Edit
{
EnableWindow(hControl, bEnableEdit);
}
if (hDeleteButton) // Delete
{
EnableWindow(hDeleteButton, bEnableDelete);
}
if (hCurrentFocus && (FALSE == IsWindowEnabled(hCurrentFocus)))
{
if (hDeleteButton == hCurrentFocus)
{
//
// If delete is disabled and contained the focus, shift it to the Add button
//
SendMessage(hDlg, DM_SETDEFID, IDC_BUTTON1, (LPARAM)0L); //lint !e534 DM_SETDEFID doesn't return error info
hControl = GetDlgItem(hDlg, IDC_BUTTON1);
if (hControl)
{
SetFocus(hControl);
}
}
else
{
//
// If all else fails set the focus to the list control
//
hControl = GetDlgItem(hDlg, IDC_LIST1);
if (hControl)
{
SetFocus(hControl);
}
}
}
}
//+----------------------------------------------------------------------------
//
// Function: CheckForDUNversusVPNNameConflicts
//
// Synopsis: This function checks the names of all of the entries in the DUN
// entry list to make sure that no entries of the same name exist
// on the VPN list since the namespace that the two types of entries
// share (ie the cms file) is a flat namespace. If an identical entry
// name exists in both lists then one will overwrite the over in the cms.
//
// Arguments: HWND hDlg - window handle of the parent window
// ListBxList * pHeadDunEntry - head of the DUN settings list
// ListBxList * pHeadVpnEntry - head of the VPN settings list
//
// Returns: BOOL - TRUE if no collision was detected, FALSE if a collision was detected
//
// History: quintinb Created 11/01/00
//
//+----------------------------------------------------------------------------
BOOL CheckForDUNversusVPNNameConflicts(HWND hDlg, ListBxList * pHeadDunEntry, ListBxList * pHeadVpnEntry)
{
if (pHeadDunEntry && pHeadVpnEntry)
{
ListBxList * pCurrentDUN = pHeadDunEntry;
while (pCurrentDUN)
{
ListBxList * pCurrentVPN = pHeadVpnEntry;
while (pCurrentVPN)
{
CMTRACE2(TEXT("Comparing %s with %s"), pCurrentVPN->szName, pCurrentDUN->szName);
if (0 == lstrcmpi(pCurrentVPN->szName, pCurrentDUN->szName))
{
//
// Collision detected
//
LPTSTR pszMsg = CmFmtMsg(g_hInstance, IDS_DUN_NAME_CONFLICT, pCurrentDUN->szName);
if (pszMsg)
{
MessageBox(hDlg, pszMsg, g_szAppTitle, MB_OK);
CmFree (pszMsg);
}
return FALSE;
}
pCurrentVPN = pCurrentVPN->next;
}
pCurrentDUN = pCurrentDUN->next;
}
}
return TRUE;
}