/* * wpa_gui - NetworkConfig class * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */ #include <cstdio> #include <QMessageBox> #include "networkconfig.h" #include "wpagui.h" enum { AUTH_NONE = 0, AUTH_IEEE8021X = 1, AUTH_WPA_PSK = 2, AUTH_WPA_EAP = 3, AUTH_WPA2_PSK = 4, AUTH_WPA2_EAP = 5 }; #define WPA_GUI_KEY_DATA "[key is configured]" NetworkConfig::NetworkConfig(QWidget *parent, const char *, bool, Qt::WFlags) : QDialog(parent) { setupUi(this); connect(authSelect, SIGNAL(activated(int)), this, SLOT(authChanged(int))); connect(cancelButton, SIGNAL(clicked()), this, SLOT(close())); connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork())); connect(encrSelect, SIGNAL(activated(const QString &)), this, SLOT(encrChanged(const QString &))); connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork())); wpagui = NULL; new_network = false; } NetworkConfig::~NetworkConfig() { } void NetworkConfig::languageChange() { retranslateUi(this); } void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel) { new_network = true; /* SSID BSSID frequency signal flags */ setCaption(sel->text(0)); ssidEdit->setText(sel->text(0)); QString flags = sel->text(4); int auth, encr = 0; if (flags.find("[WPA2-EAP") >= 0) auth = AUTH_WPA2_EAP; else if (flags.find("[WPA-EAP") >= 0) auth = AUTH_WPA_EAP; else if (flags.find("[WPA2-PSK") >= 0) auth = AUTH_WPA2_PSK; else if (flags.find("[WPA-PSK") >= 0) auth = AUTH_WPA_PSK; else auth = AUTH_NONE; if (flags.find("-CCMP") >= 0) encr = 1; else if (flags.find("-TKIP") >= 0) encr = 0; else if (flags.find("WEP") >= 0) encr = 1; else encr = 0; authSelect->setCurrentItem(auth); authChanged(auth); encrSelect->setCurrentItem(encr); getEapCapa(); } void NetworkConfig::authChanged(int sel) { pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK); bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP || sel == AUTH_WPA2_EAP; eapSelect->setEnabled(eap); identityEdit->setEnabled(eap); passwordEdit->setEnabled(eap); cacertEdit->setEnabled(eap); while (encrSelect->count()) encrSelect->removeItem(0); if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) { encrSelect->insertItem("None"); encrSelect->insertItem("WEP"); encrSelect->setCurrentItem(sel == AUTH_NONE ? 0 : 1); } else { encrSelect->insertItem("TKIP"); encrSelect->insertItem("CCMP"); encrSelect->setCurrentItem((sel == AUTH_WPA2_PSK || sel == AUTH_WPA2_EAP) ? 1 : 0); } wepEnabled(sel == AUTH_IEEE8021X); } void NetworkConfig::addNetwork() { char reply[10], cmd[256]; size_t reply_len; int id; int psklen = pskEdit->text().length(); int auth = authSelect->currentItem(); if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) { if (psklen < 8 || psklen > 64) { QMessageBox::warning(this, "wpa_gui", "WPA-PSK requires a passphrase " "of 8 to 63 characters\n" "or 64 hex digit PSK"); return; } } if (wpagui == NULL) return; memset(reply, 0, sizeof(reply)); reply_len = sizeof(reply) - 1; if (new_network) { wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len); if (reply[0] == 'F') { QMessageBox::warning(this, "wpa_gui", "Failed to add " "network to wpa_supplicant\n" "configuration."); return; } id = atoi(reply); } else id = edit_network_id; setNetworkParam(id, "ssid", ssidEdit->text().ascii(), true); const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL; switch (auth) { case AUTH_NONE: key_mgmt = "NONE"; break; case AUTH_IEEE8021X: key_mgmt = "IEEE8021X"; break; case AUTH_WPA_PSK: key_mgmt = "WPA-PSK"; proto = "WPA"; break; case AUTH_WPA_EAP: key_mgmt = "WPA-EAP"; proto = "WPA"; break; case AUTH_WPA2_PSK: key_mgmt = "WPA-PSK"; proto = "WPA2"; break; case AUTH_WPA2_EAP: key_mgmt = "WPA-EAP"; proto = "WPA2"; break; } if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP || auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) { int encr = encrSelect->currentItem(); if (encr == 0) pairwise = "TKIP"; else pairwise = "CCMP"; } if (proto) setNetworkParam(id, "proto", proto, false); if (key_mgmt) setNetworkParam(id, "key_mgmt", key_mgmt, false); if (pairwise) { setNetworkParam(id, "pairwise", pairwise, false); setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false); } if (pskEdit->isEnabled() && strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0) setNetworkParam(id, "psk", pskEdit->text().ascii(), psklen != 64); if (eapSelect->isEnabled()) setNetworkParam(id, "eap", eapSelect->currentText().ascii(), false); if (identityEdit->isEnabled()) setNetworkParam(id, "identity", identityEdit->text().ascii(), true); if (passwordEdit->isEnabled() && strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0) setNetworkParam(id, "password", passwordEdit->text().ascii(), true); if (cacertEdit->isEnabled()) setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(), true); writeWepKey(id, wep0Edit, 0); writeWepKey(id, wep1Edit, 1); writeWepKey(id, wep2Edit, 2); writeWepKey(id, wep3Edit, 3); if (wep0Radio->isEnabled() && wep0Radio->isChecked()) setNetworkParam(id, "wep_tx_keyidx", "0", false); else if (wep1Radio->isEnabled() && wep1Radio->isChecked()) setNetworkParam(id, "wep_tx_keyidx", "1", false); else if (wep2Radio->isEnabled() && wep2Radio->isChecked()) setNetworkParam(id, "wep_tx_keyidx", "2", false); else if (wep3Radio->isEnabled() && wep3Radio->isChecked()) setNetworkParam(id, "wep_tx_keyidx", "3", false); snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id); reply_len = sizeof(reply); wpagui->ctrlRequest(cmd, reply, &reply_len); if (strncmp(reply, "OK", 2) != 0) { QMessageBox::warning(this, "wpa_gui", "Failed to enable " "network in wpa_supplicant\n" "configuration."); /* Network was added, so continue anyway */ } wpagui->triggerUpdate(); wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); close(); } void NetworkConfig::setWpaGui(WpaGui *_wpagui) { wpagui = _wpagui; } int NetworkConfig::setNetworkParam(int id, const char *field, const char *value, bool quote) { char reply[10], cmd[256]; size_t reply_len; snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s", id, field, quote ? "\"" : "", value, quote ? "\"" : ""); reply_len = sizeof(reply); wpagui->ctrlRequest(cmd, reply, &reply_len); return strncmp(reply, "OK", 2) == 0 ? 0 : -1; } void NetworkConfig::encrChanged(const QString &sel) { wepEnabled(sel.find("WEP") == 0); } void NetworkConfig::wepEnabled(bool enabled) { wep0Edit->setEnabled(enabled); wep1Edit->setEnabled(enabled); wep2Edit->setEnabled(enabled); wep3Edit->setEnabled(enabled); wep0Radio->setEnabled(enabled); wep1Radio->setEnabled(enabled); wep2Radio->setEnabled(enabled); wep3Radio->setEnabled(enabled); } void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id) { char buf[10]; bool hex; const char *txt, *pos; size_t len; if (!edit->isEnabled() || edit->text().isEmpty()) return; /* * Assume hex key if only hex characters are present and length matches * with 40, 104, or 128-bit key */ txt = edit->text().ascii(); if (strcmp(txt, WPA_GUI_KEY_DATA) == 0) return; len = strlen(txt); if (len == 0) return; pos = txt; hex = true; while (*pos) { if (!((*pos >= '0' && *pos <= '9') || (*pos >= 'a' && *pos <= 'f') || (*pos >= 'A' && *pos <= 'F'))) { hex = false; break; } pos++; } if (hex && len != 10 && len != 26 && len != 32) hex = false; snprintf(buf, sizeof(buf), "wep_key%d", id); setNetworkParam(network_id, buf, txt, !hex); } static int key_value_isset(const char *reply, size_t reply_len) { return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0); } void NetworkConfig::paramsFromConfig(int network_id) { int i, res; edit_network_id = network_id; getEapCapa(); char reply[1024], cmd[256], *pos; size_t reply_len; snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; ssidEdit->setText(reply + 1); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id); reply_len = sizeof(reply) - 1; int wpa = 0; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { reply[reply_len] = '\0'; if (strstr(reply, "RSN") || strstr(reply, "WPA2")) wpa = 2; else if (strstr(reply, "WPA")) wpa = 1; } int auth = AUTH_NONE, encr = 0; snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { reply[reply_len] = '\0'; if (strstr(reply, "WPA-EAP")) auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP; else if (strstr(reply, "WPA-PSK")) auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK; else if (strstr(reply, "IEEE8021X")) { auth = AUTH_IEEE8021X; encr = 1; } } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) { reply[reply_len] = '\0'; if (strstr(reply, "CCMP")) encr = 1; else if (strstr(reply, "TKIP")) encr = 0; else if (strstr(reply, "WEP")) encr = 1; else encr = 0; } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id); reply_len = sizeof(reply) - 1; res = wpagui->ctrlRequest(cmd, reply, &reply_len); if (res >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; pskEdit->setText(reply + 1); } else if (res >= 0 && key_value_isset(reply, reply_len)) { pskEdit->setText(WPA_GUI_KEY_DATA); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; identityEdit->setText(reply + 1); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id); reply_len = sizeof(reply) - 1; res = wpagui->ctrlRequest(cmd, reply, &reply_len); if (res >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; passwordEdit->setText(reply + 1); } else if (res >= 0 && key_value_isset(reply, reply_len)) { passwordEdit->setText(WPA_GUI_KEY_DATA); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; cacertEdit->setText(reply + 1); } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) { reply[reply_len] = '\0'; for (i = 0; i < eapSelect->count(); i++) { if (eapSelect->text(i).compare(reply) == 0) { eapSelect->setCurrentItem(i); break; } } } for (i = 0; i < 4; i++) { QLineEdit *wepEdit; switch (i) { default: case 0: wepEdit = wep0Edit; break; case 1: wepEdit = wep1Edit; break; case 2: wepEdit = wep2Edit; break; case 3: wepEdit = wep3Edit; break; } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", network_id, i); reply_len = sizeof(reply) - 1; res = wpagui->ctrlRequest(cmd, reply, &reply_len); if (res >= 0 && reply_len >= 2 && reply[0] == '"') { reply[reply_len] = '\0'; pos = strchr(reply + 1, '"'); if (pos) *pos = '\0'; if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) encr = 1; wepEdit->setText(reply + 1); } else if (res >= 0 && key_value_isset(reply, reply_len)) { if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) encr = 1; wepEdit->setText(WPA_GUI_KEY_DATA); } } snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id); reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) { reply[reply_len] = '\0'; switch (atoi(reply)) { case 0: wep0Radio->setChecked(true); break; case 1: wep1Radio->setChecked(true); break; case 2: wep2Radio->setChecked(true); break; case 3: wep3Radio->setChecked(true); break; } } authSelect->setCurrentItem(auth); authChanged(auth); encrSelect->setCurrentItem(encr); if (auth == AUTH_NONE || auth == AUTH_IEEE8021X) wepEnabled(encr == 1); removeButton->setEnabled(true); addButton->setText("Save"); } void NetworkConfig::removeNetwork() { char reply[10], cmd[256]; size_t reply_len; if (QMessageBox::information(this, "wpa_gui", "This will permanently remove the " "network\n" "from the configuration. Do you really " "want\n" "to remove this network?", "Yes", "No") != 0) return; snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id); reply_len = sizeof(reply); wpagui->ctrlRequest(cmd, reply, &reply_len); if (strncmp(reply, "OK", 2) != 0) { QMessageBox::warning(this, "wpa_gui", "Failed to remove network from " "wpa_supplicant\n" "configuration."); } else { wpagui->triggerUpdate(); wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len); } close(); } void NetworkConfig::newNetwork() { new_network = true; getEapCapa(); } void NetworkConfig::getEapCapa() { char reply[256]; size_t reply_len; if (wpagui == NULL) return; reply_len = sizeof(reply) - 1; if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0) return; reply[reply_len] = '\0'; QString res(reply); QStringList types = QStringList::split(QChar(' '), res); eapSelect->insertStringList(types); }