#include #include "wzcatl.h" #include "quickcfg.h" #include "eapolcfg.h" #include "wzccore.h" #include "wzchelp.h" #define RFSH_TIMEOUT 3500 UINT g_TimerID = 373; // 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}; #define ARRAYSIZE(x) (sizeof((x)) / sizeof((x)[0])) // Enhanced message box function int DisplayFormatMessage(HWND hwnd, UINT idCaption, UINT idFormatString, UINT uType, ...); //+--------------------------------------------------------------------------- // 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 CWZCQuickCfg::GetWepKMaterial(UINT *pnKeyLen, LPBYTE *ppbKMat, DWORD *pdwCtlFlags) { DWORD dwErr = ERROR_SUCCESS; UINT nKeyLen = ::GetWindowTextLength(m_hEdtWepK); DWORD dwCtlFlags = 0; LPSTR pszKMat = NULL; // we only accept the follwing material for WEP keys: // - no text (length 0) => there is no WEP key provided // - 5 chars or 10 hexadecimal digits (5byte / 40bit key) // - 13 chars or 26 hexadecimal digits (13byte / 104bit key) // - 16 chars or 32 hexadecimal digits (16byte / 128bit key) if (nKeyLen != 0 && nKeyLen != WZC_WEPKMAT_40_ASC && nKeyLen != WZC_WEPKMAT_40_HEX && nKeyLen != WZC_WEPKMAT_104_ASC && nKeyLen != WZC_WEPKMAT_104_HEX && nKeyLen != WZC_WEPKMAT_128_ASC && nKeyLen != WZC_WEPKMAT_128_HEX) { dwErr = ERROR_INVALID_DATA; } else if (nKeyLen != 0) // the key is either ascii or hexadecimal, 40 or 104bit { dwCtlFlags = WZCCTL_WEPK_PRESENT; pszKMat = new CHAR[nKeyLen + 1]; if (pszKMat == NULL) dwErr = ERROR_NOT_ENOUGH_MEMORY; // get the current key material from the edit control if (dwErr == ERROR_SUCCESS) { if (nKeyLen != ::GetWindowTextA(m_hEdtWepK, pszKMat, nKeyLen+1)) dwErr = GetLastError(); } // now we have the key material if (dwErr == ERROR_SUCCESS) { // if the key is provided in hexadecimal digits, mark it in // the ctl flags and do the conversion if (nKeyLen == WZC_WEPKMAT_40_HEX || nKeyLen == WZC_WEPKMAT_104_HEX || nKeyLen == WZC_WEPKMAT_128_HEX) { UINT i = 0, j = 0; dwCtlFlags |= WZCCTL_WEPK_XFORMAT; while (i < nKeyLen && pszKMat[i] != '\0') { BYTE chHexByte = 0; if (!isxdigit(pszKMat[i]) || !isxdigit(pszKMat[i+1])) { dwErr = ERROR_INVALID_DATA; break; } chHexByte = HEX(pszKMat[i]) << 4; i++; chHexByte |= HEX(pszKMat[i]); i++; pszKMat[j++] = chHexByte; } // if everything went fine, since we parsed hexadecimal digits // it means the real length is half of the text length (two hexadecimal // digits per byte) if (dwErr == ERROR_SUCCESS) nKeyLen /= 2; } } } if (dwErr == ERROR_SUCCESS) { if (pdwCtlFlags != NULL) *pdwCtlFlags = dwCtlFlags; if (pnKeyLen != NULL) *pnKeyLen = nKeyLen; if (ppbKMat != NULL) *ppbKMat = (LPBYTE)pszKMat; else if (pszKMat != NULL) delete pszKMat; } else { if (pszKMat != NULL) delete pszKMat; } return dwErr; } //+--------------------------------------------------------------------- // IsConfigInList - checks whether the pwzcConfig (WZC_WLAN_CONFIG object) is // in the list provided as the first parameter. BOOL CWZCQuickCfg::IsConfigInList(CWZCConfig *pHdList, PWZC_WLAN_CONFIG pwzcConfig, CWZCConfig **ppMatchingConfig) { BOOL bYes = FALSE; if (pHdList != NULL) { CWZCConfig *pwzcCrt; pwzcCrt = pHdList; do { if (pwzcCrt->Match(pwzcConfig)) { if (ppMatchingConfig != NULL) *ppMatchingConfig = pwzcCrt; bYes = TRUE; break; } pwzcCrt = pwzcCrt->m_pNext; } while(pwzcCrt != pHdList); } return bYes; } //+--------------------------------------------------------------------- // InitListView - initializes the networks list view (doesn't fill it in) DWORD CWZCQuickCfg::InitListView() { RECT rc; LV_COLUMN lvc = {0}; DWORD dwStyle; // initialize the image list styles dwStyle = ::GetWindowLong(m_hLstNetworks, GWL_STYLE); ::SetWindowLong(m_hLstNetworks, GWL_STYLE, (dwStyle | LVS_SHAREIMAGELISTS)); // Create state image lists m_hImgs = ImageList_LoadImage( _Module.GetResourceInstance(), MAKEINTRESOURCE(IDB_WZC_LISTICONS), 16, 0, PALETTEINDEX(6), IMAGE_BITMAP, 0); ListView_SetImageList(m_hLstNetworks, m_hImgs, LVSIL_SMALL); lvc.mask = LVCF_FMT | LVCF_WIDTH; lvc.fmt = LVCFMT_LEFT; ::GetClientRect(m_hLstNetworks, &rc); lvc.cx = rc.right - GetSystemMetrics(SM_CXVSCROLL); //lvc.cx = rc.right; ListView_InsertColumn(m_hLstNetworks, 0, &lvc); ListView_SetExtendedListViewStyleEx(m_hLstNetworks, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); return ERROR_SUCCESS; } //+--------------------------------------------------------------------- // GetOIDs - gets the OIDs for the m_IntfEntry member. It assumes the // GUID is set already DWORD CWZCQuickCfg::GetOIDs(DWORD dwInFlags, LPDWORD pdwOutFlags) { DWORD dwError = ERROR_SUCCESS; DWORD dwOutFlags; if (m_IntfEntry.wszGuid == NULL) { m_IntfEntry.wszGuid = (LPWSTR)RpcCAlloc(sizeof(WCHAR)*GUID_NCH); if (m_IntfEntry.wszGuid == NULL) { dwError = GetLastError(); } else { // don't care of the return code. If getting the GUID fails (it shouldn't) // then we end up with a "0000..." GUID which will fail anyhow in the // RPC call later StringFromGUID2( m_Guid, m_IntfEntry.wszGuid, GUID_NCH); } } if (dwError == ERROR_SUCCESS) { if (dwInFlags & INTF_DESCR) { RpcFree(m_IntfEntry.wszDescr); m_IntfEntry.wszDescr = NULL; } if (dwInFlags & INTF_PREFLIST) { RpcFree(m_IntfEntry.rdStSSIDList.pData); m_IntfEntry.rdStSSIDList.dwDataLen = 0; m_IntfEntry.rdStSSIDList.pData = NULL; } if (dwInFlags & INTF_SSID) { RpcFree(m_IntfEntry.rdSSID.pData); m_IntfEntry.rdSSID.dwDataLen = 0; m_IntfEntry.rdSSID.pData = NULL; } if (dwInFlags & INTF_BSSID) { RpcFree(m_IntfEntry.rdBSSID.pData); m_IntfEntry.rdBSSID.dwDataLen = 0; m_IntfEntry.rdBSSID.pData = NULL; } if (dwInFlags & INTF_BSSIDLIST) { RpcFree(m_IntfEntry.rdBSSIDList.pData); m_IntfEntry.rdBSSIDList.dwDataLen = 0; m_IntfEntry.rdBSSIDList.pData = NULL; } dwError = WZCQueryInterface( NULL, dwInFlags, &m_IntfEntry, pdwOutFlags); } return dwError; } //+--------------------------------------------------------------------- // SavePreferredConfigs - fills in the INTF_ENTRY parameter with all // the preferred networks from the m_pHdPList DWORD CWZCQuickCfg::SavePreferredConfigs(PINTF_ENTRY pIntf, CWZCConfig *pStartCfg) { DWORD dwErr = ERROR_SUCCESS; CWZCConfig *pCrt = NULL; UINT nPrefrd = 0; if (m_pHdPList != NULL) { // count first the number of preferred entries in the list pCrt = m_pHdPList; do { nPrefrd++; pCrt = pCrt->m_pNext; } while(pCrt != m_pHdPList); } if (nPrefrd > 0) { PWZC_802_11_CONFIG_LIST pwzcPrefrdList; UINT nwzcPrefrdSize; nwzcPrefrdSize = sizeof(WZC_802_11_CONFIG_LIST)+ (nPrefrd-1)*sizeof(WZC_WLAN_CONFIG); // allocate as much memory as needed for storing all the preferred SSIDs pwzcPrefrdList = (PWZC_802_11_CONFIG_LIST)RpcCAlloc(nwzcPrefrdSize); if (pwzcPrefrdList == NULL) { dwErr = GetLastError(); } else { DWORD dwLErr; pwzcPrefrdList->NumberOfItems = 0; pwzcPrefrdList->Index = 0; // we have now all we need - start copying the preferred pCrt = m_pHdPList; do { PWZC_WLAN_CONFIG pPrefrdConfig; // if this is the configuration that needs to attempted first, // mark its index in the Index field. if (pCrt == pStartCfg) { pwzcPrefrdList->Index = pwzcPrefrdList->NumberOfItems; // save the 802.1x configuration just for the configuration we're connecting to! if (pCrt->m_pEapolConfig != NULL) { dwLErr = pCrt->m_pEapolConfig->SaveEapolConfig(m_IntfEntry.wszGuid, &(pCrt->m_wzcConfig.Ssid)); if (dwErr == ERROR_SUCCESS) dwErr = dwLErr; } } pPrefrdConfig = &(pwzcPrefrdList->Config[pwzcPrefrdList->NumberOfItems++]); CopyMemory(pPrefrdConfig, &pCrt->m_wzcConfig, sizeof(WZC_WLAN_CONFIG)); pCrt = pCrt->m_pNext; } while(pwzcPrefrdList->NumberOfItems < nPrefrd && pCrt != m_pHdPList); pIntf->rdStSSIDList.dwDataLen = nwzcPrefrdSize; pIntf->rdStSSIDList.pData = (LPBYTE)pwzcPrefrdList; } } else { pIntf->rdStSSIDList.dwDataLen = 0; pIntf->rdStSSIDList.pData = NULL; } return dwErr; } //+--------------------------------------------------------------------- // FillVisibleList - fills in the configs from the WZC_802_11_CONFIG_LIST object // into the list of visible configs DWORD CWZCQuickCfg::FillVisibleList(PWZC_802_11_CONFIG_LIST pwzcVList) { DWORD dwErr = ERROR_SUCCESS; UINT i; // cleanup whatever we might already have in the visible list if (m_pHdVList != NULL) { while (m_pHdVList->m_pNext != m_pHdVList) { delete m_pHdVList->m_pNext; } delete m_pHdVList; m_pHdVList = NULL; } if (pwzcVList != NULL) { for (i = 0; i < pwzcVList->NumberOfItems; i++) { dwErr = AddUniqueConfig( 0, // no op flags WZC_DESCR_VISIBLE, // this is a visible entry &(pwzcVList->Config[i])); // reset the error if config was just duplicated if (dwErr == ERROR_DUPLICATE_TAG) dwErr = ERROR_SUCCESS; } } return dwErr; } //+--------------------------------------------------------------------- // FillPreferredList - fills in the configs from the WZC_802_11_CONFIG_LIST object // into the list of preferred configs DWORD CWZCQuickCfg::FillPreferredList(PWZC_802_11_CONFIG_LIST pwzcPList) { DWORD dwErr = ERROR_SUCCESS; UINT i; // cleanup whatever we might already have in the preferred list if (m_pHdPList != NULL) { while (m_pHdPList ->m_pNext != m_pHdPList) { delete m_pHdPList ->m_pNext; } delete m_pHdPList; m_pHdPList = NULL; } if (pwzcPList != NULL) { for (i = 0; i < pwzcPList->NumberOfItems; i++) { PWZC_WLAN_CONFIG pwzcPConfig = &(pwzcPList->Config[i]); CWZCConfig *pVConfig = NULL; DWORD dwFlags = WZC_DESCR_PREFRD; // check whether this preferred is also visible and adjust dwFlags if so if (IsConfigInList(m_pHdVList, pwzcPConfig, &pVConfig)) { // mark the visible entry as being also preferred! // NOTE: This is why the visible list needs to be filled in first! pVConfig->m_dwFlags |= WZC_DESCR_PREFRD; dwFlags |= WZC_DESCR_VISIBLE; } dwErr = AddUniqueConfig( WZCADD_OVERWRITE, // preferred entries cause info to be overwritten dwFlags, pwzcPConfig); // reset the error if config was just duplicated if (dwErr == ERROR_DUPLICATE_TAG) dwErr = ERROR_SUCCESS; } } return dwErr; } //+--------------------------------------------------------------------------- // Adds the given configuration to the internal lists. The entries in the lists // are ordered on InfrastructureMode in descending order. This way the Infrastructure // entries will be on the top of the list while the adhoc entries will be on the // bottom. (we rely on the order as it is given in NDIS_802_11_NETWORK_INFRASTRUCTURE) DWORD CWZCQuickCfg::AddUniqueConfig( DWORD dwOpFlags, DWORD dwEntryFlags, PWZC_WLAN_CONFIG pwzcConfig, CWZCConfig **ppNewNode) { DWORD dwErr = ERROR_SUCCESS; CWZCConfig *pHdList = (dwEntryFlags & WZC_DESCR_PREFRD) ? m_pHdPList : m_pHdVList; // skip the null SSIDs from the visible list (coming from APs // not responding to broadcast SSID). if (pHdList == m_pHdVList) { UINT i = pwzcConfig->Ssid.SsidLength; for (; i > 0 && pwzcConfig->Ssid.Ssid[i-1] == 0; i--); if (i == 0) goto exit; } // if the list is currently empty, create the first entry as the head of the list if (pHdList == NULL) { pHdList = new CWZCConfig(dwEntryFlags, pwzcConfig); if (pHdList == NULL) dwErr = ERROR_NOT_ENOUGH_MEMORY; else { pHdList->m_pEapolConfig = new CEapolConfig; if (pHdList->m_pEapolConfig == NULL) dwErr = ERROR_NOT_ENOUGH_MEMORY; else dwErr = pHdList->m_pEapolConfig->LoadEapolConfig(m_IntfEntry.wszGuid, &(pHdList->m_wzcConfig.Ssid)); if (dwErr != ERROR_SUCCESS) { delete pHdList; pHdList = NULL; } } // if the caller wants, return the pointer to the newly created object if (ppNewNode != NULL) *ppNewNode = pHdList; } else { // else the list already contains at least one element CWZCConfig *pCrt, *pHdGroup; // scan the list (keep in mind it is ordered descendingly on IM) pHdGroup = pCrt = pHdList; do { // check whether we entered a new group of configs (different InfrastructureMode) if (pHdGroup->m_wzcConfig.InfrastructureMode != pCrt->m_wzcConfig.InfrastructureMode) pHdGroup = pCrt; // if found an identical entry (same SSID and same InfraMode) // signal the DUPLICATE_TAG error if (pCrt->Match(pwzcConfig)) { // merge the flags first pCrt->m_dwFlags |= dwEntryFlags; // If requested, copy over the new configuration. // If not explicitly requested, copy over only if the existent configuration // prooves to be weaker than the one being added. if (dwOpFlags & WZCADD_OVERWRITE || pCrt->Weaker(pwzcConfig)) { memcpy(&(pCrt->m_wzcConfig), pwzcConfig, sizeof(WZC_WLAN_CONFIG)); } // if the caller wants, return the pointer to the matching entry if (ppNewNode != NULL) *ppNewNode = pCrt; // signal there is already a matching config dwErr = ERROR_DUPLICATE_TAG; } pCrt = pCrt->m_pNext; } while (dwErr == ERROR_SUCCESS && pCrt != pHdList && pwzcConfig->InfrastructureMode <= pCrt->m_wzcConfig.InfrastructureMode); // if dwErr is unchanged, this means a new node has to be added ahead of pCrt node if (dwErr == ERROR_SUCCESS) { // create the new config and insert it ahead of this node. CWZCConfig *pNewConfig; pNewConfig = new CWZCConfig(dwEntryFlags, pwzcConfig); if (pNewConfig == NULL) { dwErr = ERROR_NOT_ENOUGH_MEMORY; } else { pNewConfig->m_pEapolConfig = new CEapolConfig; if (pNewConfig->m_pEapolConfig == NULL) dwErr = ERROR_NOT_ENOUGH_MEMORY; else dwErr = pNewConfig->m_pEapolConfig->LoadEapolConfig(m_IntfEntry.wszGuid, &(pNewConfig->m_wzcConfig.Ssid)); if (dwErr != ERROR_SUCCESS) { delete pNewConfig; pNewConfig = NULL; } } if (dwErr == ERROR_SUCCESS) { INT nDiff; // if asked to insert in the head of the group, pCrt should point to this head if (dwOpFlags & WZCADD_HIGROUP) pCrt = pHdGroup; pNewConfig->m_pPrev = pCrt->m_pPrev; pNewConfig->m_pNext = pCrt; pCrt->m_pPrev->m_pNext = pNewConfig; pCrt->m_pPrev = pNewConfig; // get the difference between the Infrastructure modes for the new node and // for the current head nDiff = pNewConfig->m_wzcConfig.InfrastructureMode - pHdList->m_wzcConfig.InfrastructureMode; // if the newly entered entry has the largest "key" in // the existent sequence, or it has to be inserted in the head of its group and it is // in the first group, then the global list head moves to the new entry if (nDiff > 0 || ((dwOpFlags & WZCADD_HIGROUP) && (nDiff == 0))) pHdList = pNewConfig; } // if the caller wants, return the pointer to the newly created object if (ppNewNode != NULL) *ppNewNode = pNewConfig; } } if (dwEntryFlags & WZC_DESCR_PREFRD) { m_pHdPList = pHdList; } else { m_pHdVList = pHdList; } exit: return dwErr; } //+--------------------------------------------------------------------------- // Display the Visible & Preferred lists into their controls DWORD CWZCQuickCfg::RefreshListView() { DWORD dwErr = ERROR_SUCCESS; CWZCConfig *pCrt; UINT i = 0; // clear first the list ListView_DeleteAllItems(m_hLstNetworks); // Add first VPI if (m_pHdPList != NULL) { pCrt = m_pHdPList; do { if (pCrt->m_dwFlags & WZC_DESCR_VISIBLE && pCrt->m_wzcConfig.InfrastructureMode == Ndis802_11Infrastructure) { pCrt->m_nListIndex = i; pCrt->AddConfigToListView(m_hLstNetworks, i++); } pCrt = pCrt->m_pNext; } while (pCrt != m_pHdPList); } // Add next VI if (m_pHdVList != NULL) { pCrt = m_pHdVList; do { if (!(pCrt->m_dwFlags & WZC_DESCR_PREFRD) && pCrt->m_wzcConfig.InfrastructureMode == Ndis802_11Infrastructure) { pCrt->m_nListIndex = i; pCrt->AddConfigToListView(m_hLstNetworks, i++); } pCrt = pCrt->m_pNext; } while (pCrt != m_pHdVList); } // Add now VPA if (m_pHdPList != NULL) { pCrt = m_pHdPList; do { if (pCrt->m_dwFlags & WZC_DESCR_VISIBLE && pCrt->m_wzcConfig.InfrastructureMode == Ndis802_11IBSS) { pCrt->m_nListIndex = i; pCrt->AddConfigToListView(m_hLstNetworks, i++); } pCrt = pCrt->m_pNext; } while (pCrt != m_pHdPList); } // Add now VA if (m_pHdVList != NULL) { pCrt = m_pHdVList; do { if (!(pCrt->m_dwFlags & WZC_DESCR_PREFRD) && pCrt->m_wzcConfig.InfrastructureMode == Ndis802_11IBSS) { pCrt->m_nListIndex = i; pCrt->AddConfigToListView(m_hLstNetworks, i++); } pCrt = pCrt->m_pNext; } while (pCrt != m_pHdVList); } ListView_SetItemState(m_hLstNetworks, 0, LVIS_SELECTED, LVIS_SELECTED); ListView_EnsureVisible(m_hLstNetworks, 0, FALSE); return dwErr; } DWORD CWZCQuickCfg::RefreshControls() { DWORD dwError = ERROR_SUCCESS; CWZCConfig *pConfig = NULL; LVITEM lvi = {0}; INT iSelected; BOOL bEnableWepCtrls = FALSE; UINT nKLen = 0; UINT nCheckOneX = BST_UNCHECKED; BOOL bEnableOneX = FALSE; // get the selected item from the visible list iSelected = ListView_GetNextItem(m_hLstNetworks, -1, LVNI_SELECTED); if (iSelected >= 0) { lvi.mask = LVIF_PARAM; lvi.iItem = iSelected; if (ListView_GetItem(m_hLstNetworks, &lvi)) { pConfig = (CWZCConfig*)lvi.lParam; } } else { ::EnableWindow(m_hBtnConnect, FALSE); return dwError; } // since we just switched the networks, yes, the wep key can be seen as touched. // If we find out there is already a key available, we'll reset this flag and go // with that one until the user is clicking it. m_bKMatTouched = TRUE; if (pConfig != NULL) { CWZCConfig *pVConfig; // pick up the "privacy" bit from the matching visible configuration // NOTE: The test below should always succeed actually if (IsConfigInList(m_pHdVList, &(pConfig->m_wzcConfig), &pVConfig)) bEnableWepCtrls = (pVConfig->m_wzcConfig.Privacy != 0); else bEnableWepCtrls = (pConfig->m_wzcConfig.Privacy != 0); if (pConfig->m_dwFlags & WZC_DESCR_PREFRD && pConfig->m_wzcConfig.dwCtlFlags & WZCCTL_WEPK_PRESENT && pConfig->m_wzcConfig.KeyLength > 0) { //--- when a password is to be displayed as hidden chars, don't put in //--- its actual length, but just 8 bulled chars. nKLen = 8; m_bKMatTouched = FALSE; } if (bEnableWepCtrls) { // For networks requiring privacy, 802.1X is going to be by default disabled and // locked out on all IBSS networks. if (pConfig->m_wzcConfig.InfrastructureMode == Ndis802_11IBSS) { nCheckOneX = BST_UNCHECKED; bEnableOneX = FALSE; } else { // for all non-preferred Infrastructure networks, 802.1X is going to be by default // enabled since these networks start with "the key is provided for me automatically" // which suggests 802.1X. if (!(pConfig->m_dwFlags & WZC_DESCR_PREFRD)) { nCheckOneX = BST_CHECKED; } else // this is a preferred Infrastructure network { // initial 802.1X state is the one from the profile nCheckOneX = pConfig->m_pEapolConfig->Is8021XEnabled() ? BST_CHECKED: BST_UNCHECKED; } // for Infrastructure networks requiring privacy, user is allowed to change 802.1X state bEnableOneX = TRUE; } } } g_wszHiddWepK[nKLen] = L'\0'; ::SetWindowText(m_hEdtWepK, g_wszHiddWepK); ::SetWindowText(m_hEdtWepK2, g_wszHiddWepK); g_wszHiddWepK[nKLen] = 0x25cf; if (bEnableWepCtrls) { CheckDlgButton(IDC_WZCQCFG_CHK_ONEX, nCheckOneX); ::EnableWindow(m_hChkOneX, bEnableOneX); if (::IsWindowEnabled(m_hEdtWepK2)) { ::EnableWindow(m_hLblWepK2, FALSE); ::EnableWindow(m_hEdtWepK2, FALSE); } if (::IsWindowVisible(m_hLblNoWepKInfo)) { ::ShowWindow(m_hWarnIcon, SW_HIDE); ::ShowWindow(m_hLblNoWepKInfo, SW_HIDE); ::ShowWindow(m_hChkNoWepK, SW_HIDE); } if (!::IsWindowVisible(m_hLblWepKInfo)) { ::ShowWindow(m_hLblWepKInfo, SW_SHOW); ::ShowWindow(m_hLblWepK, SW_SHOW); ::ShowWindow(m_hEdtWepK, SW_SHOW); ::ShowWindow(m_hLblWepK2, SW_SHOW); ::ShowWindow(m_hEdtWepK2, SW_SHOW); ::ShowWindow(m_hChkOneX, SW_SHOW); } } else { if (::IsWindowVisible(m_hLblWepKInfo)) { ::ShowWindow(m_hLblWepKInfo, SW_HIDE); ::ShowWindow(m_hLblWepK, SW_HIDE); ::ShowWindow(m_hEdtWepK, SW_HIDE); ::ShowWindow(m_hLblWepK2, SW_HIDE); ::ShowWindow(m_hEdtWepK2, SW_HIDE); ::ShowWindow(m_hChkOneX, SW_HIDE); } if (!::IsWindowVisible(m_hLblNoWepKInfo)) { ::ShowWindow(m_hWarnIcon, SW_SHOW); ::ShowWindow(m_hLblNoWepKInfo, SW_SHOW); ::ShowWindow(m_hChkNoWepK, SW_SHOW); CheckDlgButton(IDC_WZCQCFG_CHK_NOWK,BST_UNCHECKED); } pConfig = NULL; // reset the pointer to the configuration to force disable the "Connect" button } ::EnableWindow(m_hBtnConnect, pConfig != NULL); return dwError; } //+--------------------------------------------------------------------------- // class constructor CWZCQuickCfg::CWZCQuickCfg(const GUID * pGuid) { // initialize the UI handles m_hLblInfo = NULL; m_hLblNetworks = NULL; m_hLstNetworks = NULL; m_hLblWepKInfo = NULL; m_hLblWepK = NULL; m_hEdtWepK = NULL; m_hLblWepK2 = NULL; m_hEdtWepK2 = NULL; m_hChkOneX = NULL; m_hWarnIcon = NULL; m_hLblNoWepKInfo = NULL; m_hChkNoWepK = NULL; m_hBtnAdvanced = NULL; m_hBtnConnect = NULL; // initialize the Images handle m_hImgs = NULL; // initialize the WZC data m_bHaveWZCData = FALSE; ZeroMemory(&m_IntfEntry, sizeof(INTF_ENTRY)); m_dwOIDFlags = 0; m_nTimer = 0; m_hCursor = NULL; if (pGuid != NULL) m_Guid = *pGuid; else ZeroMemory(&m_Guid, sizeof(GUID)); // init the internal list heads m_pHdVList = NULL; m_pHdPList = NULL; // init the connection m_wszTitle = NULL; } //+--------------------------------------------------------------------------- // class destructor CWZCQuickCfg::~CWZCQuickCfg() { if (m_hImgs != NULL) ImageList_Destroy(m_hImgs); // delete the internal INTF_ENTRY object WZCDeleteIntfObj(&m_IntfEntry); // delete the internal list of visible configurations // (is like filling it with NULL) FillVisibleList(NULL); // delete the internal list of preferred configurations // (is like filling it with NULL) FillPreferredList(NULL); if (m_nTimer != 0) KillTimer(m_nTimer); } //+--------------------------------------------------------------------------- // INIT_DIALOG handler LRESULT CWZCQuickCfg::OnInitDialog (UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { DWORD dwError; DWORD dwInFlags; BOOL bEnableAll; m_bKMatTouched = TRUE; // reference the UI controls m_hLblInfo = GetDlgItem(IDC_WZCQCFG_LBL_INFO); m_hLblNetworks = GetDlgItem(IDC_WZCQCFG_LBL_NETWORKS); m_hLstNetworks = GetDlgItem(IDC_WZCQCFG_NETWORKS); m_hLblWepKInfo = GetDlgItem(IDC_WZCQCFG_LBL_WKINFO); m_hLblWepK = GetDlgItem(IDC_WZCQCFG_LBL_WEPK); m_hEdtWepK = GetDlgItem(IDC_WZCQCFG_WEPK); m_hLblWepK2 = GetDlgItem(IDC_WZCQCFG_LBL_WEPK2); m_hEdtWepK2 = GetDlgItem(IDC_WZCQCFG_WEPK2); m_hChkOneX = GetDlgItem(IDC_WZCQCFG_CHK_ONEX); m_hWarnIcon = GetDlgItem(IDC_WZCQCFG_ICO_WARN); m_hLblNoWepKInfo = GetDlgItem(IDC_WZCQCFG_LBL_NOWKINFO); m_hChkNoWepK = GetDlgItem(IDC_WZCQCFG_CHK_NOWK); m_hBtnAdvanced = GetDlgItem(IDC_WZCQCFG_ADVANCED); m_hBtnConnect = GetDlgItem(IDC_WZCQCFG_CONNECT); if (m_wszTitle != NULL) SetWindowText(m_wszTitle); if (m_hWarnIcon != NULL) ::SendMessage(m_hWarnIcon, STM_SETICON, (WPARAM)LoadIcon(NULL, IDI_WARNING), (LPARAM)0); // sets the icon images for the list view InitListView(); CenterWindow(); m_dwOIDFlags = 0; dwInFlags = INTF_BSSIDLIST|INTF_PREFLIST|INTF_ALL_FLAGS; dwError = GetOIDs(dwInFlags,&m_dwOIDFlags); if (m_dwOIDFlags == dwInFlags) { // if the OIDs are supported, fill in everything. if (m_IntfEntry.dwCtlFlags & INTFCTL_OIDSSUPP) { // add the list of visible configs for this adapter FillVisibleList((PWZC_802_11_CONFIG_LIST)m_IntfEntry.rdBSSIDList.pData); // add the list of preferred configs for this adapter FillPreferredList((PWZC_802_11_CONFIG_LIST)m_IntfEntry.rdStSSIDList.pData); // fill in the list view RefreshListView(); m_hCursor = SetCursor(LoadCursor(NULL, IDC_ARROW)); // and enable all controls bEnableAll = TRUE; } } else { // switch the cursor to "App starting" m_hCursor = SetCursor(LoadCursor(NULL, IDC_APPSTARTING)); // we should fill in the UI after Tr (see the WZC state machine) // Tr is 3secs (defined in ..zeroconf\server\state.h) m_nTimer = (UINT)SetTimer(g_TimerID, RFSH_TIMEOUT); bEnableAll = FALSE; } // now that the UI is filled up set the remaining controls to their // respective states. RefreshControls(); ::EnableWindow(m_hLblInfo, bEnableAll); ::EnableWindow(m_hLblNetworks, bEnableAll); ::EnableWindow(m_hLstNetworks, bEnableAll); ::EnableWindow(m_hBtnAdvanced, bEnableAll); ::SetFocus(m_hLstNetworks); bHandled = TRUE; return 0; } //+--------------------------------------------------------------------------- // Help handlers extern const WCHAR c_szNetCfgHelpFile[]; LRESULT CWZCQuickCfg::OnContextMenu(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { ::WinHelp(m_hWnd, c_wszWzcHelpFile, HELP_CONTEXTMENU, (ULONG_PTR)g_aHelpIDs_IDD_WZCQCFG); bHandled = TRUE; return 0; } LRESULT CWZCQuickCfg::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_wszWzcHelpFile, HELP_WM_HELP, (ULONG_PTR)g_aHelpIDs_IDD_WZCQCFG); bHandled = TRUE; } return 0; } //+--------------------------------------------------------------------- // Refresh timer handler LRESULT CWZCQuickCfg::OnTimer(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled) { if (m_nTimer != 0) { BOOL bEnableAll; DWORD dwInFlags; // switch the cursor back to whatever it was SetCursor(LoadCursor(NULL, IDC_ARROW)); KillTimer(m_nTimer); m_nTimer = 0; m_dwOIDFlags = 0; dwInFlags = INTF_BSSIDLIST|INTF_PREFLIST|INTF_ALL_FLAGS; GetOIDs(dwInFlags,&m_dwOIDFlags); bEnableAll = (m_dwOIDFlags == dwInFlags) && (m_IntfEntry.dwCtlFlags & INTFCTL_OIDSSUPP); if (bEnableAll) { // add the list of visible configs for this adapter FillVisibleList((PWZC_802_11_CONFIG_LIST)m_IntfEntry.rdBSSIDList.pData); // add the list of preferred configs for this adapter FillPreferredList((PWZC_802_11_CONFIG_LIST)m_IntfEntry.rdStSSIDList.pData); // fill in the list view RefreshListView(); } // now that the UI is filled up set the remaining controls to their // respective states. RefreshControls(); // enable all the UI when done refreshing ::EnableWindow(m_hLblInfo, bEnableAll); ::EnableWindow(m_hLblNetworks, bEnableAll); ::EnableWindow(m_hLstNetworks, bEnableAll); ::EnableWindow(m_hBtnAdvanced, bEnableAll); } return 0; } //+--------------------------------------------------------------------- // Selection changed in the list LRESULT CWZCQuickCfg::OnItemChanged( int idCtrl, LPNMHDR pnmh, BOOL& bHandled) { bHandled = TRUE; RefreshControls(); ::SetFocus(m_hLstNetworks); return 0; } //+--------------------------------------------------------------------- // User clicked an entry in the list LRESULT CWZCQuickCfg::OnDbClick(int idCtrl, LPNMHDR pnmh, BOOL& bHandled) { if (idCtrl == IDC_WZCQCFG_NETWORKS && ::IsWindowEnabled(m_hBtnConnect)) { OnConnect( (WORD)pnmh->code, (WORD)pnmh->idFrom, pnmh->hwndFrom, bHandled); } return 0; } //+--------------------------------------------------------------------------- // OnConnect button handler LRESULT CWZCQuickCfg::OnConnect(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { DWORD dwErr = ERROR_SUCCESS; INT iSelected; CWZCConfig *pConfig = NULL; UINT nKeyLen; LPBYTE pbKMat = NULL; DWORD dwCtlFlags; BOOL bOkToDismiss = TRUE; // get the selected item from the visible list iSelected = ListView_GetNextItem(m_hLstNetworks, -1, LVNI_SELECTED); if (iSelected < 0) dwErr = ERROR_GEN_FAILURE; // iSelected should be 0 otherwise "Connect" won't be enabled if (dwErr == ERROR_SUCCESS) { LVITEM lvi = {0}; lvi.mask = LVIF_PARAM; lvi.iItem = iSelected; if (ListView_GetItem(m_hLstNetworks, &lvi)) { pConfig = (CWZCConfig*)lvi.lParam; if (pConfig == NULL) dwErr = ERROR_GEN_FAILURE; } else dwErr = ERROR_GEN_FAILURE; } if (dwErr == ERROR_SUCCESS) { // here we should have a valid pConfig ASSERT(pConfig); if ((m_IntfEntry.dwCtlFlags & INTFCTL_CM_MASK) != Ndis802_11AutoUnknown && (m_IntfEntry.dwCtlFlags & INTFCTL_CM_MASK) != pConfig->m_wzcConfig.InfrastructureMode) { // User is trying to access a network type (infra or adhoc) that they're not allowed to access. // Give them an error message UINT idMessage = (pConfig->m_wzcConfig.InfrastructureMode == Ndis802_11Infrastructure) ? IDS_CANTACCESSNET_INFRA : IDS_CANTACCESSNET_ADHOC; WCHAR szSSID[MAX_PATH]; ListView_GetItemText(m_hLstNetworks, iSelected, 0, szSSID, ARRAYSIZE(szSSID)); DisplayFormatMessage(m_hWnd, IDS_WZCERR_CAPTION, idMessage, MB_ICONERROR | MB_OK, szSSID); // Can't connect - error dwErr = ERROR_GEN_FAILURE; // Don't close the dialog bOkToDismiss = FALSE; } } // get the WEP key only if the user touched it. m_bKMatTouched is FALSE only when the configuration // selected is already in the preferred list and that preferred config already contained a key which was // not touched a bit by the user. Otherwise it is TRUE. if (dwErr == ERROR_SUCCESS && m_bKMatTouched) { UINT nIdsErr; // check whether the WEP key has the right format dwErr = GetWepKMaterial(&nKeyLen, &pbKMat, &dwCtlFlags); if (dwErr != ERROR_SUCCESS) { ::SendMessage(m_hEdtWepK, EM_SETSEL, 0, (LPARAM)-1); ::SetFocus(m_hEdtWepK); nIdsErr = IDS_WZCERR_INVALID_WEPK; } // check whether the WEP key is confirmed correctly if (dwErr == ERROR_SUCCESS && nKeyLen > 0) { WCHAR wszWepK1[32], wszWepK2[32]; UINT nKeyLen1, nKeyLen2; nKeyLen1 = ::GetWindowText(m_hEdtWepK, wszWepK1, sizeof(wszWepK1)/sizeof(WCHAR)); nKeyLen2 = ::GetWindowText(m_hEdtWepK2, wszWepK2, sizeof(wszWepK2)/sizeof(WCHAR)); if (nKeyLen1 != nKeyLen2 || nKeyLen1 == 0 || wcscmp(wszWepK1, wszWepK2) != 0) { nIdsErr = IDS_WZCERR_MISMATCHED_WEPK; ::SetWindowText(m_hEdtWepK2, L""); ::SetFocus(m_hEdtWepK2); dwErr = ERROR_INVALID_DATA; } } if (dwErr != ERROR_SUCCESS) { WCHAR wszBuffer[MAX_PATH]; WCHAR wszCaption[MAX_PATH]; LoadString(nIdsErr == IDS_WZCERR_INVALID_WEPK ? _Module.GetResourceInstance() : WZCGetSPResModule(), nIdsErr, wszBuffer, MAX_PATH); LoadString(_Module.GetResourceInstance(), IDS_WZCERR_CAPTION, wszCaption, MAX_PATH); MessageBox(wszBuffer, wszCaption, MB_ICONERROR|MB_OK); bOkToDismiss = FALSE; } } // we do have the right WEP key here, lets copy it to the corresponding config if (dwErr == ERROR_SUCCESS) { // if this configuration is not a preferred one, copy it in the preferred // list at the top of its group if (!(pConfig->m_dwFlags & WZC_DESCR_PREFRD)) { // move this configuration out of the visible list pConfig->m_pNext->m_pPrev = pConfig->m_pPrev; pConfig->m_pPrev->m_pNext = pConfig->m_pNext; // if the list head pointed on this config, move it to // the next in the list if (m_pHdVList == pConfig) m_pHdVList = pConfig->m_pNext; // if the list head still points on the same config, // it means this was the only one in the list. So, null out the head. if (m_pHdVList == pConfig) m_pHdVList = NULL; //next insert this visible config in the preferred list if (m_pHdPList == NULL) { m_pHdPList = pConfig; pConfig->m_pNext = pConfig; pConfig->m_pPrev = pConfig; } else { CWZCConfig *pCrt; // the new preferred config comes on top of the list if: // (it is infrastructure) or (there are no infrastructures in the preferred list) if (pConfig->m_wzcConfig.InfrastructureMode == Ndis802_11Infrastructure || m_pHdPList->m_wzcConfig.InfrastructureMode == Ndis802_11IBSS) { pCrt = m_pHdPList; m_pHdPList = pConfig; } else // it definitely doesn't come the first in the list { for (pCrt = m_pHdPList->m_pNext; pCrt != m_pHdPList; pCrt=pCrt->m_pNext) { // if this is the first configuration in the matching group break the loop if (pCrt->m_wzcConfig.InfrastructureMode == Ndis802_11IBSS) break; } } // now we have to insert pConfig in the front of pCrt; pConfig->m_pNext = pCrt; pConfig->m_pPrev = pCrt->m_pPrev; pConfig->m_pNext->m_pPrev = pConfig; pConfig->m_pPrev->m_pNext = pConfig; } } // if the configuration is a preferred one, just make sure we copy over the // privacy bit from the visible list. That one is the "real" thing else { CWZCConfig *pVConfig; if (IsConfigInList(m_pHdVList, &pConfig->m_wzcConfig, &pVConfig)) { pConfig->m_wzcConfig.Privacy = pVConfig->m_wzcConfig.Privacy; } } // now the configuration is at its right position - put in the new WEP key, if any was typed in if (pConfig->m_wzcConfig.Privacy && m_bKMatTouched) { // if no key is provided, it means there is no key material. // All we do is to reset the corresponding bit - whatever material was there // will be preserved along with its length & format if (!(dwCtlFlags & WZCCTL_WEPK_PRESENT)) { pConfig->m_wzcConfig.dwCtlFlags &= ~WZCCTL_WEPK_PRESENT; } else { // now if we have a WEP key, copy over its control flags and material pConfig->m_wzcConfig.dwCtlFlags = dwCtlFlags; ZeroMemory(pConfig->m_wzcConfig.KeyMaterial, WZCCTL_MAX_WEPK_MATERIAL); pConfig->m_wzcConfig.KeyLength = nKeyLen; memcpy(pConfig->m_wzcConfig.KeyMaterial, pbKMat, nKeyLen); } } } // if all 802.11 params have been taken care of, copy now the 802.1x params (if needed) if (dwErr == ERROR_SUCCESS && pConfig->m_pEapolConfig != NULL) { // if the network is an infrastructure one fix the 802.1X state. // For ad hoc networks don't touch the 802.1x since it might mess the setting for a // corresponding Infrastructure network (802.1X doesn't differentiate between SSID Infra & SSID ad hoc) // 802.1X engine is smart enough to not act on ad hoc networks regardless its registry state! if (pConfig->m_wzcConfig.InfrastructureMode == Ndis802_11Infrastructure) { // if the network requires privacy, set its state according to the "Enable 802.1X" checkbox if (pConfig->m_wzcConfig.Privacy) { pConfig->m_pEapolConfig->Set8021XState(IsDlgButtonChecked(IDC_WZCQCFG_CHK_ONEX) == BST_CHECKED); } else // if the network doesn't require privacy - disable 802.1X! { // if the network is either ad hoc or infrastructure with no wep // explicitly disable 802.1x pConfig->m_pEapolConfig->Set8021XState(0); } } } // ok, save the preferred list back to Wireless Zero Configuration Service if (dwErr == ERROR_SUCCESS) { RpcFree(m_IntfEntry.rdStSSIDList.pData); m_IntfEntry.rdStSSIDList.dwDataLen = 0; m_IntfEntry.rdStSSIDList.pData = NULL; dwErr = SavePreferredConfigs(&m_IntfEntry, pConfig); } if (dwErr == ERROR_SUCCESS) { // by saving the preferred list here we're forcing a hard reset to // the WZC State machine. This is what we want since we're here // as a consequence of a failure and a user intervention. dwErr = WZCSetInterface( NULL, INTF_PREFLIST, &m_IntfEntry, NULL); if (dwErr == ERROR_PARTIAL_COPY) { DisplayFormatMessage( m_hWnd, IDS_WZCERR_CAPTION, IDS_WZC_PARTIAL_APPLY, MB_ICONEXCLAMATION|MB_OK); dwErr = ERROR_SUCCESS; } } // in case of any failure we might want to warn the user (another popup?) // the question is what is the user supposed to do in such a case? if (dwErr != ERROR_SUCCESS) { dwErr = ERROR_SUCCESS; } if(pbKMat != NULL) delete pbKMat; if (bOkToDismiss) { bHandled = TRUE; SpEndDialog(IDOK); } return 0; } //+--------------------------------------------------------------------------- // OK button handler LRESULT CWZCQuickCfg::OnCancel(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { bHandled = TRUE; SpEndDialog(IDCANCEL); return 0; } //+--------------------------------------------------------------------------- // Advanced button handler LRESULT CWZCQuickCfg::OnAdvanced(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { bHandled = TRUE; SpEndDialog(IDC_WZCQCFG_ADVANCED); return 0; } int DisplayFormatMessage(HWND hwnd, UINT idCaption, UINT idFormatString, UINT uType, ...) { int iResult = IDCANCEL; TCHAR szError[1024 + 1]; *szError = 0; TCHAR szCaption[256 + 1]; TCHAR szFormat[1024 + 1]; *szFormat = 0; // Load and format the error body if (LoadString(WZCGetSPResModule(), idFormatString, szFormat, ARRAYSIZE(szFormat))) { va_list arguments; va_start(arguments, uType); if (FormatMessage(FORMAT_MESSAGE_FROM_STRING, szFormat, 0, 0, szError, ARRAYSIZE(szError), &arguments)) { // Load the caption if (LoadString(_Module.GetResourceInstance(), idCaption, szCaption, ARRAYSIZE(szCaption))) { iResult = MessageBox(hwnd, szError, szCaption, uType); } } va_end(arguments); } return iResult; } //+--------------------------------------------------------------------------- // Notification handler for the wep key edit text box LRESULT CWZCQuickCfg::OnWepKMatCmd(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { if (wNotifyCode == EN_SETFOCUS) { if (!m_bKMatTouched) { // the user has just clicked for the first time on an existent key.. clear out the fields, // standing for "The key is provided automatically" ::SetWindowText(m_hEdtWepK, L""); ::SetWindowText(m_hEdtWepK2, L""); ::EnableWindow(m_hLblWepK2, FALSE); // disable confirmation label for empty key ::EnableWindow(m_hEdtWepK2, FALSE); // disable confirmation edit for empty key m_bKMatTouched = TRUE; // if the 802.1X checkbox is enabled then we do have to check it here! if (::IsWindowEnabled(m_hChkOneX)) CheckDlgButton(IDC_WZCQCFG_CHK_ONEX, BST_CHECKED); } } if (wNotifyCode == EN_CHANGE) { UINT nKMatLen = ::GetWindowTextLength(m_hEdtWepK); if (!::IsWindowEnabled(m_hEdtWepK2) && nKMatLen > 0) { // user just typed in some key material - enable the confirmation text ::EnableWindow(m_hLblWepK2, TRUE); ::EnableWindow(m_hEdtWepK2, TRUE); // also uncheck 802.1x checkbox if (::IsWindowEnabled(m_hChkOneX)) CheckDlgButton(IDC_WZCQCFG_CHK_ONEX, BST_UNCHECKED); } if (::IsWindowEnabled(m_hEdtWepK2) && nKMatLen == 0) { // user just deleted all of the key material - switching to // "The key is provided for me automatically" ::SetWindowText(m_hEdtWepK2, L""); ::EnableWindow(m_hLblWepK2, FALSE); ::EnableWindow(m_hEdtWepK2, FALSE); // auto key suggests 802.1X if (::IsWindowEnabled(m_hChkOneX)) CheckDlgButton(IDC_WZCQCFG_CHK_ONEX, BST_CHECKED); } } return 0; } LRESULT CWZCQuickCfg::OnCheckConfirmNoWep(WORD wNotifyCode, WORD wID, HWND hWndCtl, BOOL& bHandled) { ::EnableWindow(m_hBtnConnect, IsDlgButtonChecked(IDC_WZCQCFG_CHK_NOWK) == BST_CHECKED); return 0; }