|
|
//+----------------------------------------------------------------------------
//
// 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; }
|