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