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