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