Home | History | Annotate | Download | only in wpa_gui-qt4
      1 /*
      2  * wpa_gui - NetworkConfig class
      3  * Copyright (c) 2005-2006, Jouni Malinen <j (at) w1.fi>
      4  *
      5  * This program is free software; you can redistribute it and/or modify
      6  * it under the terms of the GNU General Public License version 2 as
      7  * published by the Free Software Foundation.
      8  *
      9  * Alternatively, this software may be distributed under the terms of BSD
     10  * license.
     11  *
     12  * See README and COPYING for more details.
     13  */
     14 
     15 #include <cstdio>
     16 #include <QMessageBox>
     17 
     18 #include "networkconfig.h"
     19 #include "wpagui.h"
     20 
     21 enum {
     22     AUTH_NONE = 0,
     23     AUTH_IEEE8021X = 1,
     24     AUTH_WPA_PSK = 2,
     25     AUTH_WPA_EAP = 3,
     26     AUTH_WPA2_PSK = 4,
     27     AUTH_WPA2_EAP = 5
     28 };
     29 
     30 #define WPA_GUI_KEY_DATA "[key is configured]"
     31 
     32 
     33 NetworkConfig::NetworkConfig(QWidget *parent, const char *, bool, Qt::WFlags)
     34 	: QDialog(parent)
     35 {
     36 	setupUi(this);
     37 
     38 	connect(authSelect, SIGNAL(activated(int)), this,
     39 		SLOT(authChanged(int)));
     40 	connect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
     41 	connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
     42 	connect(encrSelect, SIGNAL(activated(const QString &)), this,
     43 		SLOT(encrChanged(const QString &)));
     44 	connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork()));
     45 
     46 	wpagui = NULL;
     47 	new_network = false;
     48 }
     49 
     50 
     51 NetworkConfig::~NetworkConfig()
     52 {
     53 }
     54 
     55 
     56 void NetworkConfig::languageChange()
     57 {
     58 	retranslateUi(this);
     59 }
     60 
     61 
     62 void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel)
     63 {
     64 	new_network = true;
     65 
     66 	/* SSID BSSID frequency signal flags */
     67 	setCaption(sel->text(0));
     68 	ssidEdit->setText(sel->text(0));
     69 
     70 	QString flags = sel->text(4);
     71 	int auth, encr = 0;
     72 	if (flags.find("[WPA2-EAP") >= 0)
     73 		auth = AUTH_WPA2_EAP;
     74 	else if (flags.find("[WPA-EAP") >= 0)
     75 		auth = AUTH_WPA_EAP;
     76 	else if (flags.find("[WPA2-PSK") >= 0)
     77 		auth = AUTH_WPA2_PSK;
     78 	else if (flags.find("[WPA-PSK") >= 0)
     79 		auth = AUTH_WPA_PSK;
     80 	else
     81 		auth = AUTH_NONE;
     82 
     83 	if (flags.find("-CCMP") >= 0)
     84 		encr = 1;
     85 	else if (flags.find("-TKIP") >= 0)
     86 		encr = 0;
     87 	else if (flags.find("WEP") >= 0)
     88 		encr = 1;
     89 	else
     90 		encr = 0;
     91 
     92 	authSelect->setCurrentItem(auth);
     93 	authChanged(auth);
     94 	encrSelect->setCurrentItem(encr);
     95 
     96 	getEapCapa();
     97 }
     98 
     99 
    100 void NetworkConfig::authChanged(int sel)
    101 {
    102 	pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK);
    103 	bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP ||
    104 		sel == AUTH_WPA2_EAP;
    105 	eapSelect->setEnabled(eap);
    106 	identityEdit->setEnabled(eap);
    107 	passwordEdit->setEnabled(eap);
    108 	cacertEdit->setEnabled(eap);
    109 
    110 	while (encrSelect->count())
    111 		encrSelect->removeItem(0);
    112 
    113 	if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) {
    114 		encrSelect->insertItem("None");
    115 		encrSelect->insertItem("WEP");
    116 		encrSelect->setCurrentItem(sel == AUTH_NONE ? 0 : 1);
    117 	} else {
    118 		encrSelect->insertItem("TKIP");
    119 		encrSelect->insertItem("CCMP");
    120 		encrSelect->setCurrentItem((sel == AUTH_WPA2_PSK ||
    121 					    sel == AUTH_WPA2_EAP) ? 1 : 0);
    122 	}
    123 
    124 	wepEnabled(sel == AUTH_IEEE8021X);
    125 }
    126 
    127 
    128 void NetworkConfig::addNetwork()
    129 {
    130 	char reply[10], cmd[256];
    131 	size_t reply_len;
    132 	int id;
    133 	int psklen = pskEdit->text().length();
    134 	int auth = authSelect->currentItem();
    135 
    136 	if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) {
    137 		if (psklen < 8 || psklen > 64) {
    138 			QMessageBox::warning(this, "wpa_gui",
    139 					     "WPA-PSK requires a passphrase "
    140 					     "of 8 to 63 characters\n"
    141 					     "or 64 hex digit PSK");
    142 			return;
    143 		}
    144 	}
    145 
    146 	if (wpagui == NULL)
    147 		return;
    148 
    149 	memset(reply, 0, sizeof(reply));
    150 	reply_len = sizeof(reply) - 1;
    151 
    152 	if (new_network) {
    153 		wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len);
    154 		if (reply[0] == 'F') {
    155 			QMessageBox::warning(this, "wpa_gui", "Failed to add "
    156 					     "network to wpa_supplicant\n"
    157 					     "configuration.");
    158 			return;
    159 		}
    160 		id = atoi(reply);
    161 	} else
    162 		id = edit_network_id;
    163 
    164 	setNetworkParam(id, "ssid", ssidEdit->text().ascii(), true);
    165 
    166 	const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL;
    167 	switch (auth) {
    168 	case AUTH_NONE:
    169 		key_mgmt = "NONE";
    170 		break;
    171 	case AUTH_IEEE8021X:
    172 		key_mgmt = "IEEE8021X";
    173 		break;
    174 	case AUTH_WPA_PSK:
    175 		key_mgmt = "WPA-PSK";
    176 		proto = "WPA";
    177 		break;
    178 	case AUTH_WPA_EAP:
    179 		key_mgmt = "WPA-EAP";
    180 		proto = "WPA";
    181 		break;
    182 	case AUTH_WPA2_PSK:
    183 		key_mgmt = "WPA-PSK";
    184 		proto = "WPA2";
    185 		break;
    186 	case AUTH_WPA2_EAP:
    187 		key_mgmt = "WPA-EAP";
    188 		proto = "WPA2";
    189 		break;
    190 	}
    191 
    192 	if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP ||
    193 	    auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) {
    194 		int encr = encrSelect->currentItem();
    195 		if (encr == 0)
    196 			pairwise = "TKIP";
    197 		else
    198 			pairwise = "CCMP";
    199 	}
    200 
    201 	if (proto)
    202 		setNetworkParam(id, "proto", proto, false);
    203 	if (key_mgmt)
    204 		setNetworkParam(id, "key_mgmt", key_mgmt, false);
    205 	if (pairwise) {
    206 		setNetworkParam(id, "pairwise", pairwise, false);
    207 		setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
    208 	}
    209 	if (pskEdit->isEnabled() &&
    210 	    strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
    211 		setNetworkParam(id, "psk", pskEdit->text().ascii(),
    212 				psklen != 64);
    213 	if (eapSelect->isEnabled())
    214 		setNetworkParam(id, "eap", eapSelect->currentText().ascii(),
    215 				false);
    216 	if (identityEdit->isEnabled())
    217 		setNetworkParam(id, "identity", identityEdit->text().ascii(),
    218 				true);
    219 	if (passwordEdit->isEnabled() &&
    220 	    strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
    221 		setNetworkParam(id, "password", passwordEdit->text().ascii(),
    222 				true);
    223 	if (cacertEdit->isEnabled())
    224 		setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(),
    225 				true);
    226 	writeWepKey(id, wep0Edit, 0);
    227 	writeWepKey(id, wep1Edit, 1);
    228 	writeWepKey(id, wep2Edit, 2);
    229 	writeWepKey(id, wep3Edit, 3);
    230 
    231 	if (wep0Radio->isEnabled() && wep0Radio->isChecked())
    232 		setNetworkParam(id, "wep_tx_keyidx", "0", false);
    233 	else if (wep1Radio->isEnabled() && wep1Radio->isChecked())
    234 		setNetworkParam(id, "wep_tx_keyidx", "1", false);
    235 	else if (wep2Radio->isEnabled() && wep2Radio->isChecked())
    236 		setNetworkParam(id, "wep_tx_keyidx", "2", false);
    237 	else if (wep3Radio->isEnabled() && wep3Radio->isChecked())
    238 		setNetworkParam(id, "wep_tx_keyidx", "3", false);
    239 
    240 	snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id);
    241 	reply_len = sizeof(reply);
    242 	wpagui->ctrlRequest(cmd, reply, &reply_len);
    243 	if (strncmp(reply, "OK", 2) != 0) {
    244 		QMessageBox::warning(this, "wpa_gui", "Failed to enable "
    245 				     "network in wpa_supplicant\n"
    246 				     "configuration.");
    247 		/* Network was added, so continue anyway */
    248 	}
    249 	wpagui->triggerUpdate();
    250 	wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
    251 
    252 	close();
    253 }
    254 
    255 
    256 void NetworkConfig::setWpaGui(WpaGui *_wpagui)
    257 {
    258 	wpagui = _wpagui;
    259 }
    260 
    261 
    262 int NetworkConfig::setNetworkParam(int id, const char *field,
    263 				   const char *value, bool quote)
    264 {
    265 	char reply[10], cmd[256];
    266 	size_t reply_len;
    267 	snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s",
    268 		 id, field, quote ? "\"" : "", value, quote ? "\"" : "");
    269 	reply_len = sizeof(reply);
    270 	wpagui->ctrlRequest(cmd, reply, &reply_len);
    271 	return strncmp(reply, "OK", 2) == 0 ? 0 : -1;
    272 }
    273 
    274 
    275 void NetworkConfig::encrChanged(const QString &sel)
    276 {
    277 	wepEnabled(sel.find("WEP") == 0);
    278 }
    279 
    280 
    281 void NetworkConfig::wepEnabled(bool enabled)
    282 {
    283 	wep0Edit->setEnabled(enabled);
    284 	wep1Edit->setEnabled(enabled);
    285 	wep2Edit->setEnabled(enabled);
    286 	wep3Edit->setEnabled(enabled);
    287 	wep0Radio->setEnabled(enabled);
    288 	wep1Radio->setEnabled(enabled);
    289 	wep2Radio->setEnabled(enabled);
    290 	wep3Radio->setEnabled(enabled);
    291 }
    292 
    293 
    294 void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id)
    295 {
    296 	char buf[10];
    297 	bool hex;
    298 	const char *txt, *pos;
    299 	size_t len;
    300 
    301 	if (!edit->isEnabled() || edit->text().isEmpty())
    302 		return;
    303 
    304 	/*
    305 	 * Assume hex key if only hex characters are present and length matches
    306 	 * with 40, 104, or 128-bit key
    307 	 */
    308 	txt = edit->text().ascii();
    309 	if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
    310 		return;
    311 	len = strlen(txt);
    312 	if (len == 0)
    313 		return;
    314 	pos = txt;
    315 	hex = true;
    316 	while (*pos) {
    317 		if (!((*pos >= '0' && *pos <= '9') ||
    318 		      (*pos >= 'a' && *pos <= 'f') ||
    319 		      (*pos >= 'A' && *pos <= 'F'))) {
    320 			hex = false;
    321 			break;
    322 		}
    323 		pos++;
    324 	}
    325 	if (hex && len != 10 && len != 26 && len != 32)
    326 		hex = false;
    327 	snprintf(buf, sizeof(buf), "wep_key%d", id);
    328 	setNetworkParam(network_id, buf, txt, !hex);
    329 }
    330 
    331 
    332 static int key_value_isset(const char *reply, size_t reply_len)
    333 {
    334     return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
    335 }
    336 
    337 
    338 void NetworkConfig::paramsFromConfig(int network_id)
    339 {
    340 	int i, res;
    341 
    342 	edit_network_id = network_id;
    343 	getEapCapa();
    344 
    345 	char reply[1024], cmd[256], *pos;
    346 	size_t reply_len;
    347 
    348 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
    349 	reply_len = sizeof(reply) - 1;
    350 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
    351 	    reply_len >= 2 && reply[0] == '"') {
    352 		reply[reply_len] = '\0';
    353 		pos = strchr(reply + 1, '"');
    354 		if (pos)
    355 			*pos = '\0';
    356 		ssidEdit->setText(reply + 1);
    357 	}
    358 
    359 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
    360 	reply_len = sizeof(reply) - 1;
    361 	int wpa = 0;
    362 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
    363 		reply[reply_len] = '\0';
    364 		if (strstr(reply, "RSN") || strstr(reply, "WPA2"))
    365 			wpa = 2;
    366 		else if (strstr(reply, "WPA"))
    367 			wpa = 1;
    368 	}
    369 
    370 	int auth = AUTH_NONE, encr = 0;
    371 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
    372 	reply_len = sizeof(reply) - 1;
    373 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
    374 		reply[reply_len] = '\0';
    375 		if (strstr(reply, "WPA-EAP"))
    376 			auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP;
    377 		else if (strstr(reply, "WPA-PSK"))
    378 			auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK;
    379 		else if (strstr(reply, "IEEE8021X")) {
    380 			auth = AUTH_IEEE8021X;
    381 			encr = 1;
    382 		}
    383 	}
    384 
    385 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
    386 	reply_len = sizeof(reply) - 1;
    387 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
    388 		reply[reply_len] = '\0';
    389 		if (strstr(reply, "CCMP"))
    390 			encr = 1;
    391 		else if (strstr(reply, "TKIP"))
    392 			encr = 0;
    393 		else if (strstr(reply, "WEP"))
    394 			encr = 1;
    395 		else
    396 			encr = 0;
    397 	}
    398 
    399 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
    400 	reply_len = sizeof(reply) - 1;
    401 	res = wpagui->ctrlRequest(cmd, reply, &reply_len);
    402 	if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
    403 		reply[reply_len] = '\0';
    404 		pos = strchr(reply + 1, '"');
    405 		if (pos)
    406 			*pos = '\0';
    407 		pskEdit->setText(reply + 1);
    408 	} else if (res >= 0 && key_value_isset(reply, reply_len)) {
    409 		pskEdit->setText(WPA_GUI_KEY_DATA);
    410 	}
    411 
    412 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
    413 	reply_len = sizeof(reply) - 1;
    414 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
    415 	    reply_len >= 2 && reply[0] == '"') {
    416 		reply[reply_len] = '\0';
    417 		pos = strchr(reply + 1, '"');
    418 		if (pos)
    419 			*pos = '\0';
    420 		identityEdit->setText(reply + 1);
    421 	}
    422 
    423 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
    424 	reply_len = sizeof(reply) - 1;
    425 	res = wpagui->ctrlRequest(cmd, reply, &reply_len);
    426 	if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
    427 		reply[reply_len] = '\0';
    428 		pos = strchr(reply + 1, '"');
    429 		if (pos)
    430 			*pos = '\0';
    431 		passwordEdit->setText(reply + 1);
    432 	} else if (res >= 0 && key_value_isset(reply, reply_len)) {
    433 		passwordEdit->setText(WPA_GUI_KEY_DATA);
    434 	}
    435 
    436 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
    437 	reply_len = sizeof(reply) - 1;
    438 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
    439 	    reply_len >= 2 && reply[0] == '"') {
    440 		reply[reply_len] = '\0';
    441 		pos = strchr(reply + 1, '"');
    442 		if (pos)
    443 			*pos = '\0';
    444 		cacertEdit->setText(reply + 1);
    445 	}
    446 
    447 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
    448 	reply_len = sizeof(reply) - 1;
    449 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
    450 	    reply_len >= 1) {
    451 		reply[reply_len] = '\0';
    452 		for (i = 0; i < eapSelect->count(); i++) {
    453 			if (eapSelect->text(i).compare(reply) == 0) {
    454 				eapSelect->setCurrentItem(i);
    455 				break;
    456 			}
    457 		}
    458 	}
    459 
    460 	for (i = 0; i < 4; i++) {
    461 		QLineEdit *wepEdit;
    462 		switch (i) {
    463 		default:
    464 		case 0:
    465 			wepEdit = wep0Edit;
    466 			break;
    467 		case 1:
    468 			wepEdit = wep1Edit;
    469 			break;
    470 		case 2:
    471 			wepEdit = wep2Edit;
    472 			break;
    473 		case 3:
    474 			wepEdit = wep3Edit;
    475 			break;
    476 		}
    477 		snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d",
    478 			 network_id, i);
    479 		reply_len = sizeof(reply) - 1;
    480 		res = wpagui->ctrlRequest(cmd, reply, &reply_len);
    481 		if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
    482 			reply[reply_len] = '\0';
    483 			pos = strchr(reply + 1, '"');
    484 			if (pos)
    485 				*pos = '\0';
    486 			if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
    487 				encr = 1;
    488 
    489 			wepEdit->setText(reply + 1);
    490 		} else if (res >= 0 && key_value_isset(reply, reply_len)) {
    491 			if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
    492 				encr = 1;
    493 			wepEdit->setText(WPA_GUI_KEY_DATA);
    494 		}
    495 	}
    496 
    497 	snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
    498 	reply_len = sizeof(reply) - 1;
    499 	if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1)
    500 	{
    501 		reply[reply_len] = '\0';
    502 		switch (atoi(reply)) {
    503 		case 0:
    504 			wep0Radio->setChecked(true);
    505 			break;
    506 		case 1:
    507 			wep1Radio->setChecked(true);
    508 			break;
    509 		case 2:
    510 			wep2Radio->setChecked(true);
    511 			break;
    512 		case 3:
    513 			wep3Radio->setChecked(true);
    514 			break;
    515 		}
    516 	}
    517 
    518 	authSelect->setCurrentItem(auth);
    519 	authChanged(auth);
    520 	encrSelect->setCurrentItem(encr);
    521 	if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
    522 		wepEnabled(encr == 1);
    523 
    524 	removeButton->setEnabled(true);
    525 	addButton->setText("Save");
    526 }
    527 
    528 
    529 void NetworkConfig::removeNetwork()
    530 {
    531 	char reply[10], cmd[256];
    532 	size_t reply_len;
    533 
    534 	if (QMessageBox::information(this, "wpa_gui",
    535 				     "This will permanently remove the "
    536 				     "network\n"
    537 				     "from the configuration. Do you really "
    538 				     "want\n"
    539 				     "to remove this network?", "Yes", "No")
    540 	    != 0)
    541 		return;
    542 
    543 	snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
    544 	reply_len = sizeof(reply);
    545 	wpagui->ctrlRequest(cmd, reply, &reply_len);
    546 	if (strncmp(reply, "OK", 2) != 0) {
    547 		QMessageBox::warning(this, "wpa_gui",
    548 				     "Failed to remove network from "
    549 				     "wpa_supplicant\n"
    550 				     "configuration.");
    551 	} else {
    552 		wpagui->triggerUpdate();
    553 		wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
    554 	}
    555 
    556 	close();
    557 }
    558 
    559 
    560 void NetworkConfig::newNetwork()
    561 {
    562 	new_network = true;
    563 	getEapCapa();
    564 }
    565 
    566 
    567 void NetworkConfig::getEapCapa()
    568 {
    569 	char reply[256];
    570 	size_t reply_len;
    571 
    572 	if (wpagui == NULL)
    573 		return;
    574 
    575 	reply_len = sizeof(reply) - 1;
    576 	if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0)
    577 		return;
    578 	reply[reply_len] = '\0';
    579 
    580 	QString res(reply);
    581 	QStringList types = QStringList::split(QChar(' '), res);
    582 	eapSelect->insertStringList(types);
    583 }
    584