#include "pch.h" #pragma hdrstop #include "ncnetcon.h" #include "ncperms.h" #include "ncui.h" #include "lanui.h" #include "xpsp1res.h" #include "lanhelp.h" #include "eapolui.h" #include "wzcpage.h" #include "wzcui.h" #define ARRAYSIZE(x) (sizeof((x)) / sizeof((x)[0])) //////////////////////////////////////////////////////////////////////// // CWZCConfigPage related stuff // // g_wszHiddWebK is a string of 26 bullets (0x25cf - the hidden password char) and a NULL WCHAR g_wszHiddWepK[] = {0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x25cf, 0x0000}; //+--------------------------------------------------------------------------- // automatically enable/disable state for all the WepK related controls DWORD CWZCConfigPage::EnableWepKControls() { BOOL bEnable; // allow changing the Wep Key settings only if they are needed (i.e. privacy and/or shared auth) // It is so for several reasons: // - we allow all the params to change, but the SSID & the infra mode (these are // the key info for a configuration and determines the position of the configuration // in the preferred list - messing with these involves a whole work to readjust // the position of the configuration) // - for the long term future we could allow any params of a configuration to change // including the key info. This will involve changing the position of this configuration // in the preferred list, but we should do it some time. bEnable = (m_dwFlags & WZCDLG_PROPS_RWWEP); bEnable = bEnable && ((BST_CHECKED == ::SendMessage(m_hwndUsePW, BM_GETCHECK, 0, 0)) || (BST_CHECKED == ::SendMessage(m_hwndChkShared, BM_GETCHECK, 0, 0))); ::EnableWindow(m_hwndUseHardwarePW, bEnable); bEnable = bEnable && (BST_UNCHECKED == IsDlgButtonChecked(IDC_USEHARDWAREPW)); ::EnableWindow(m_hwndLblKMat, bEnable); ::EnableWindow(m_hwndEdKMat, bEnable); ::EnableWindow(m_hwndLblKMat2, bEnable && m_bKMatTouched); ::EnableWindow(m_hwndEdKMat2, bEnable && m_bKMatTouched); ::EnableWindow(m_hwndLblKIdx, bEnable); ::EnableWindow(m_hwndEdKIdx, bEnable); return ERROR_SUCCESS; } //+--------------------------------------------------------------------------- // initializes WEP controls DWORD CWZCConfigPage::InitWepKControls() { UINT nWepKLen = 0; // check whether the key is provided automatically or not CheckDlgButton(IDC_USEHARDWAREPW, (m_wzcConfig.dwCtlFlags & WZCCTL_WEPK_PRESENT) ? BST_UNCHECKED : BST_CHECKED); if (m_wzcConfig.KeyLength == 0) { nWepKLen = 0; m_bKMatTouched = TRUE; } //--- when a password is to be displayed as hidden chars, don't put in //--- its actual length, but just 8 bulled chars. else { nWepKLen = 8; } g_wszHiddWepK[nWepKLen] = L'\0'; ::SetWindowText(m_hwndEdKMat, g_wszHiddWepK); ::SetWindowText(m_hwndEdKMat2, g_wszHiddWepK); g_wszHiddWepK[nWepKLen] = 0x25cf; // Hidden password char (bullet) // the index edit control shouldn't accept more than exactly one char ::SendMessage(m_hwndEdKIdx, EM_LIMITTEXT, 1, 0); // show the current key index, if valid. Otherwise, default to the min valid value. if (m_wzcConfig.KeyIndex + 1 >= WZC_WEPKIDX_MIN && m_wzcConfig.KeyIndex + 1 <= WZC_WEPKIDX_MAX) { CHAR szIdx[WZC_WEPKIDX_NDIGITS]; ::SetWindowTextA(m_hwndEdKIdx, _itoa(m_wzcConfig.KeyIndex + 1, szIdx, 10)); } else m_wzcConfig.KeyIndex = 0; return ERROR_SUCCESS; } //+--------------------------------------------------------------------------- // checks the validity of the WEP Key material and selects the // material from the first invalid char (non hexa in hexa format or longer // than the specified length DWORD CWZCConfigPage::CheckWepKMaterial(LPSTR *ppszKMat, DWORD *pdwKeyFlags) { DWORD dwErr = ERROR_SUCCESS; DWORD dwKeyFlags = 0; UINT nMatLen = ::GetWindowTextLength(m_hwndEdKMat); LPSTR pszCrtMat = NULL; UINT nSelIdx = 0; switch(nMatLen) { case WZC_WEPKMAT_40_ASC: // 5 chars case WZC_WEPKMAT_104_ASC: // 13 chars case WZC_WEPKMAT_128_ASC: // 16 chars break; case WZC_WEPKMAT_40_HEX: // 10 hexadecimal digits case WZC_WEPKMAT_104_HEX: // 26 hexadecimal digits case WZC_WEPKMAT_128_HEX: // 32 hexadecimal digits dwKeyFlags |= WZCCTL_WEPK_XFORMAT; break; default: dwErr = ERROR_BAD_FORMAT; } // allocate space for the current key material if (dwErr == ERROR_SUCCESS) { pszCrtMat = new CHAR[nMatLen + 1]; if (pszCrtMat == NULL) dwErr = ERROR_NOT_ENOUGH_MEMORY; } // get the current key material from the edit control if (dwErr == ERROR_SUCCESS) { if (nMatLen != ::GetWindowTextA(m_hwndEdKMat, pszCrtMat, nMatLen+1)) dwErr = GetLastError(); } // we have now all the data. We should select the text in the Key material // edit control from the first one of the two: // - the nNewLen to the end (if the current content exceeds the specified length) // - the first non hexa digit to the end (if current format is hexa) if (dwErr == ERROR_SUCCESS && (dwKeyFlags & WZCCTL_WEPK_XFORMAT)) { UINT nNonXIdx; for (nNonXIdx = 0; nNonXIdx < nMatLen; nNonXIdx++) { if (!isxdigit(pszCrtMat[nNonXIdx])) { dwErr = ERROR_BAD_FORMAT; break; } } } if (dwErr != ERROR_SUCCESS) { ::SetWindowText(m_hwndEdKMat2, L""); ::SendMessage(m_hwndEdKMat, EM_SETSEL, (WPARAM)0, (LPARAM)-1); // and set the focus on the key material edit control ::SetFocus(m_hwndEdKMat); // clean up whatever memory we allocated since we're not passing it up if (pszCrtMat != NULL) delete [] pszCrtMat; } else { *ppszKMat = pszCrtMat; *pdwKeyFlags = dwKeyFlags; } return dwErr; } //+--------------------------------------------------------------------------- // parses & copies the WEP Key material from the parameter into the m_wzcConfig object // The length should be already the good one, the format is given by m_wzcConfig.dwCtlFlags // Since we assume a valid key material it means its length is non-zero and it is fitting in // the configurations key material buffer, and if the formatting is hexadecimal, it // contains an even number of hexa digits. DWORD CWZCConfigPage::CopyWepKMaterial(LPSTR szKMat) { BYTE chFakeKeyMaterial[] = {0x56, 0x09, 0x08, 0x98, 0x4D, 0x08, 0x11, 0x66, 0x42, 0x03, 0x01, 0x67, 0x66}; if (m_wzcConfig.dwCtlFlags & WZCCTL_WEPK_XFORMAT) { UINT nKMatIdx = 0; // we know here we have a valid hexadecimal formatting // this implies the string has an even number of digits while(*szKMat != '\0') { m_wzcConfig.KeyMaterial[nKMatIdx] = HEX(*szKMat) << 4; szKMat++; m_wzcConfig.KeyMaterial[nKMatIdx] |= HEX(*szKMat); szKMat++; nKMatIdx++; } m_wzcConfig.KeyLength = nKMatIdx; } else { // the key is not in Hex format, so just copy over the bytes // we know the length is good so no worries about overwritting the buffer m_wzcConfig.KeyLength = strlen(szKMat); memcpy(m_wzcConfig.KeyMaterial, szKMat, m_wzcConfig.KeyLength); } return ERROR_SUCCESS; } //+--------------------------------------------------------------------------- // sets the EAPOL Locked bit DWORD CWZCConfigPage::SetEapolAllowedState() { if (m_pEapolConfig != NULL) { // EAPOL shouldn't be even allowed on networks not requesting privacy or on // ad hoc networks. if (BST_UNCHECKED == ::SendMessage(m_hwndUsePW, BM_GETCHECK, 0, 0) || BST_CHECKED == ::SendMessage(m_hwndChkAdhoc, BM_GETCHECK, 0, 0)) { // lock the Eapol configuration page m_pEapolConfig->m_dwCtlFlags |= EAPOL_CTL_LOCKED; } else // for Infrastructure networks requiring privacy.. { // unlock the Eapol configuration page (users are allowed to enable / disable 802.1X) m_pEapolConfig->m_dwCtlFlags &= ~EAPOL_CTL_LOCKED; // if asked to correlate onex state with the presence of an explicit key, fix this here if (m_dwFlags & WZCDLG_PROPS_ONEX_CHECK) { if (BST_CHECKED == ::SendMessage(m_hwndUseHardwarePW, BM_GETCHECK, 0, 0)) m_pEapolConfig->m_EapolIntfParams.dwEapFlags |= EAPOL_ENABLED; else m_pEapolConfig->m_EapolIntfParams.dwEapFlags &= ~EAPOL_ENABLED; } } } return ERROR_SUCCESS; } //+--------------------------------------------------------------------------- // class constructor CWZCConfigPage::CWZCConfigPage(DWORD dwFlags) { m_dwFlags = dwFlags; m_bKMatTouched = FALSE; m_pEapolConfig = NULL; ZeroMemory(&m_wzcConfig, sizeof(WZC_WLAN_CONFIG)); m_wzcConfig.Length = sizeof(WZC_WLAN_CONFIG); m_wzcConfig.InfrastructureMode = Ndis802_11Infrastructure; m_wzcConfig.Privacy = 1; } //+--------------------------------------------------------------------------- // Uploads the configuration into the dialog's internal data DWORD CWZCConfigPage::UploadWzcConfig(CWZCConfig *pwzcConfig) { // if the configuration being uploaded is already a preferred one, reset the // ONEX check flag (don't control the ONEX setting since it has already been // chosen by the user at the moment the configuration was first created) if (pwzcConfig->m_dwFlags & WZC_DESCR_PREFRD) m_dwFlags &= ~WZCDLG_PROPS_ONEX_CHECK; CopyMemory(&m_wzcConfig, &(pwzcConfig->m_wzcConfig), sizeof(WZC_WLAN_CONFIG)); return ERROR_SUCCESS; } //+--------------------------------------------------------------------------- // copy a reference to the EAPOL configuration object DWORD CWZCConfigPage::UploadEapolConfig(CEapolConfig *pEapolConfig) { // this member is never to be freed in this class m_pEapolConfig = pEapolConfig; return ERROR_SUCCESS; } //+--------------------------------------------------------------------------- // Sets the dialog flags. Returns the entire current set of flags DWORD CWZCConfigPage::SetFlags(DWORD dwMask, DWORD dwNewFlags) { m_dwFlags &= ~dwMask; m_dwFlags |= (dwNewFlags & dwMask); return m_dwFlags; } //+--------------------------------------------------------------------------- // INIT_DIALOG handler LRESULT CWZCConfigPage::OnInitDialog (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { DWORD dwStyle; HRESULT hr = S_OK; // get all the controls handles m_hwndEdSSID = GetDlgItem(IDC_WZC_EDIT_SSID); m_hwndChkAdhoc = GetDlgItem(IDC_ADHOC); m_hwndChkShared = GetDlgItem(IDC_SHAREDMODE); m_hwndUsePW = GetDlgItem(IDC_USEPW); // wep key related controls m_hwndUseHardwarePW = GetDlgItem(IDC_USEHARDWAREPW); m_hwndLblKMat = GetDlgItem(IDC_WZC_LBL_KMat); m_hwndEdKMat = GetDlgItem(IDC_WZC_EDIT_KMat); m_hwndLblKMat2 = GetDlgItem(IDC_WZC_LBL_KMat2); m_hwndEdKMat2 = GetDlgItem(IDC_WZC_EDIT_KMat2); m_hwndLblKIdx = GetDlgItem(IDC_WZC_LBL_KIdx); m_hwndEdKIdx = GetDlgItem(IDC_WZC_EDIT_KIdx); // initialize the SSID field with the SSID, if one is given if (m_wzcConfig.Ssid.SsidLength != 0) { // ugly but this is life. In order to convert the SSID to LPWSTR we need a buffer. // We know an SSID can't exceed 32 chars (see NDIS_802_11_SSID from ntddndis.h) so // make room for the null terminator and that's it. We could do mem alloc but I'm // not sure it worth the effort (at runtime). WCHAR wszSSID[33]; UINT nLenSSID = 0; // convert the LPSTR (original SSID format) to LPWSTR (needed in List Ctrl) nLenSSID = MultiByteToWideChar( CP_ACP, 0, (LPCSTR)m_wzcConfig.Ssid.Ssid, m_wzcConfig.Ssid.SsidLength, wszSSID, celems(wszSSID)); if (nLenSSID != 0) { wszSSID[nLenSSID] = L'\0'; ::SetWindowText(m_hwndEdSSID, wszSSID); } } // Check the "this network is adhoc" box if neccessary. ::SendMessage(m_hwndChkAdhoc, BM_SETCHECK, (m_wzcConfig.InfrastructureMode == Ndis802_11IBSS) ? BST_CHECKED : BST_UNCHECKED, 0); // Check the "Use the network key to access this network" checkbox if necessary // Checking this corresponds to "Shared" auth mode. Unchecked corresponds to "Open" (dsheldon) ::SendMessage(m_hwndChkShared, BM_SETCHECK, m_wzcConfig.AuthenticationMode ? BST_CHECKED : BST_UNCHECKED, 0); // the SSID can't be under any circumstances larger than 32 chars ::SendMessage(m_hwndEdSSID, EM_LIMITTEXT, 32, 0); // create the spin control CreateUpDownControl( WS_CHILD|WS_VISIBLE|WS_BORDER|UDS_SETBUDDYINT|UDS_ALIGNRIGHT|UDS_NOTHOUSANDS|UDS_ARROWKEYS, 0, 0, 0, 0, m_hWnd, -1, _Module.GetResourceInstance(), m_hwndEdKIdx, WZC_WEPKIDX_MAX, WZC_WEPKIDX_MIN, WZC_WEPKIDX_MIN); ::SendMessage(m_hwndUsePW, BM_SETCHECK, (m_wzcConfig.Privacy == 1) ? BST_CHECKED : BST_UNCHECKED, 0); // at this point we can say the WEP key is untouched m_bKMatTouched = FALSE; // fill in the WepK controls InitWepKControls(); // enable or disable the controls based on how the dialog is called ::EnableWindow(m_hwndEdSSID, m_dwFlags & WZCDLG_PROPS_RWSSID); ::EnableWindow(m_hwndChkAdhoc, m_dwFlags & WZCDLG_PROPS_RWINFR); ::EnableWindow(m_hwndChkShared, m_dwFlags & WZCDLG_PROPS_RWAUTH); ::EnableWindow(m_hwndUsePW, m_dwFlags & WZCDLG_PROPS_RWWEP); // enable or disable all the wep key related controls EnableWepKControls(); SetEapolAllowedState(); return LresFromHr(hr); } //+--------------------------------------------------------------------------- // OK button handler LRESULT CWZCConfigPage::OnOK(UINT idCtrl, LPNMHDR pnmh, BOOL& bHandled) { UINT nSSIDLen; CHAR szSSID[33]; DWORD dwKeyFlags = 0; UINT nKeyIdx; LPSTR szWepKMat = NULL; // variables used for prompting the user with warning/error messages UINT nWarnStringID = 0; WCHAR wszBuff[48]; m_wzcConfig.Length = sizeof(WZC_WLAN_CONFIG); // get the basic 802.11 parameters m_wzcConfig.InfrastructureMode = (BST_CHECKED == ::SendMessage(m_hwndChkAdhoc, BM_GETCHECK, 0, 0)) ? Ndis802_11IBSS : Ndis802_11Infrastructure; m_wzcConfig.AuthenticationMode = (BST_CHECKED == ::SendMessage(m_hwndChkShared, BM_GETCHECK, 0, 0)) ? Ndis802_11AuthModeShared : Ndis802_11AuthModeOpen; m_wzcConfig.Privacy = (BYTE) (BST_CHECKED == ::SendMessage(m_hwndUsePW, BM_GETCHECK, 0, 0)) ? 1 : 0; // get the SSID (max 32 chars) nSSIDLen = ::GetWindowTextA( m_hwndEdSSID, szSSID, sizeof(szSSID)); m_wzcConfig.Ssid.SsidLength = nSSIDLen; if (nSSIDLen > 0) CopyMemory(m_wzcConfig.Ssid.Ssid, szSSID, nSSIDLen); // mark whether a WEP key is provided (not defaulted) or not (defaulted to whatever the hdw might have) if (IsDlgButtonChecked(IDC_USEHARDWAREPW)) m_wzcConfig.dwCtlFlags &= ~WZCCTL_WEPK_PRESENT; else m_wzcConfig.dwCtlFlags |= WZCCTL_WEPK_PRESENT; // get the key index in a local variable wszBuff[0] = L'\0'; ::GetWindowText(m_hwndEdKIdx, wszBuff, sizeof(wszBuff)/sizeof(WCHAR)); nKeyIdx = _wtoi(wszBuff) - 1; if (nKeyIdx + 1 < WZC_WEPKIDX_MIN || nKeyIdx + 1 > WZC_WEPKIDX_MAX) { nWarnStringID = IDS_WZC_KERR_IDX; nKeyIdx = m_wzcConfig.KeyIndex; ::SendMessage(m_hwndEdKIdx, EM_SETSEL, 0, -1); ::SetFocus(m_hwndEdKIdx); } // get the key material in a local variable. // If the key is incorrect, the local storage is not changed. if (m_bKMatTouched) { if (CheckWepKMaterial(&szWepKMat, &dwKeyFlags) != ERROR_SUCCESS) { nWarnStringID = IDS_WZC_KERR_MAT; } else { CHAR szBuff[WZC_WEPKMAT_128_HEX + 1]; // maximum key length // verify whether the key is confirmed correctly. We do this only if nWarnString is // 0, which means the key is formatted correctly, hence less than 32 chars. szBuff[0] = '\0'; ::GetWindowTextA( m_hwndEdKMat2, szBuff, sizeof(szBuff)); if (strcmp(szBuff, szWepKMat) != 0) { nWarnStringID = IDS_WZCERR_MISMATCHED_WEPK; // no wep key to be saved, hence delete whatever was read so far delete szWepKMat; szWepKMat = NULL; ::SetWindowText(m_hwndEdKMat2, L""); ::SetFocus(m_hwndEdKMat2); } } } // check whether we actually need the wep key settings entered by the user if ((m_wzcConfig.AuthenticationMode == Ndis802_11AuthModeOpen && !m_wzcConfig.Privacy) || !(m_wzcConfig.dwCtlFlags & WZCCTL_WEPK_PRESENT)) { // no, we don't actually need the key, so we won't prompt the user if he entered an incorrect // key material or index. In this case whatever the user entered is simply ignored. // However, if the user entered a correct index / material, they will be saved. nWarnStringID = 0; } // if there is no error to be prompted, just copy over the key settings (regardless they are needed // or not). if (nWarnStringID == 0) { m_wzcConfig.KeyIndex = nKeyIdx; if (szWepKMat != NULL) { m_wzcConfig.dwCtlFlags &= ~(WZCCTL_WEPK_XFORMAT); m_wzcConfig.dwCtlFlags |= dwKeyFlags; CopyWepKMaterial(szWepKMat); } } else { //NcMsgBox( // WZCGetSPResModule(), // m_hWnd, // IDS_LANUI_ERROR_CAPTION, // nWarnStringID, // MB_ICONSTOP|MB_OK); WCHAR pszCaption[256]; WCHAR pszText[1024]; LoadString(WZCGetSPResModule(), IDS_LANUI_ERROR_CAPTION, pszCaption, celems(pszCaption)); LoadString(nWarnStringID == IDS_WZC_KERR_MAT ? WZCGetDlgResModule() : WZCGetSPResModule(), nWarnStringID == IDS_WZC_KERR_MAT ? 5002 : nWarnStringID, pszText, celems(pszText)); ::MessageBox (m_hWnd, pszText, pszCaption, MB_ICONSTOP|MB_OK); } if (szWepKMat != NULL) delete szWepKMat; bHandled = TRUE; if (nWarnStringID == 0) { return PSNRET_NOERROR; } else { return PSNRET_INVALID_NOCHANGEPAGE; } } //+--------------------------------------------------------------------------- // Context sensitive help handler extern const WCHAR c_szNetCfgHelpFile[]; LRESULT CWZCConfigPage::OnContextMenu( UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& fHandled) { ::WinHelp(m_hWnd, c_szNetCfgHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)g_aHelpIDs_IDC_WZC_DLG_PROPS); return 0; } LRESULT CWZCConfigPage::OnHelp(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { LPHELPINFO lphi = reinterpret_cast(lParam); if (HELPINFO_WINDOW == lphi->iContextType) { ::WinHelp(static_cast(lphi->hItemHandle), c_szNetCfgHelpFile, HELP_WM_HELP, (ULONG_PTR)g_aHelpIDs_IDC_WZC_DLG_PROPS); } return 0; } //+--------------------------------------------------------------------------- // Handler for enabling/disabling WEP LRESULT CWZCConfigPage::OnUsePW(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { EnableWepKControls(); SetEapolAllowedState(); return 0; } //+--------------------------------------------------------------------------- // Handler for enabling controls if the user wants to specify key material (password) explicitly LRESULT CWZCConfigPage::OnUseHWPassword(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { EnableWepKControls(); SetEapolAllowedState(); return 0; } //+--------------------------------------------------------------------------- // Handler for detecting changes in the key material LRESULT CWZCConfigPage::OnWepKMatCmd(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { if (wNotifyCode == EN_SETFOCUS) { if (!m_bKMatTouched) { ::SetWindowText(m_hwndEdKMat, L""); ::SetWindowText(m_hwndEdKMat2, L""); ::EnableWindow(m_hwndLblKMat2, TRUE); ::EnableWindow(m_hwndEdKMat2, TRUE); m_bKMatTouched = TRUE; } } return 0; } //+--------------------------------------------------------------------------- LRESULT CWZCConfigPage::OnCheckEapolAllowed(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { return SetEapolAllowedState(); }