813c5edf8ad619f07f074ecee1a37f34671f0c51
[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                 const char *eap =
235                         eapSelect->currentText().toAscii().constData();
236                 setNetworkParam(id, "eap", eap, false);
237                 if (strcmp(eap, "SIM") == 0 || strcmp(eap, "AKA") == 0)
238                         setNetworkParam(id, "pcsc", "", true);
239         }
240         if (identityEdit->isEnabled())
241                 setNetworkParam(id, "identity",
242                                 identityEdit->text().toAscii().constData(),
243                                 true);
244         if (passwordEdit->isEnabled() &&
245             strcmp(passwordEdit->text().toAscii().constData(),
246                    WPA_GUI_KEY_DATA) != 0)
247                 setNetworkParam(id, "password",
248                                 passwordEdit->text().toAscii().constData(),
249                                 true);
250         if (cacertEdit->isEnabled())
251                 setNetworkParam(id, "ca_cert",
252                                 cacertEdit->text().toAscii().constData(),
253                                 true);
254         writeWepKey(id, wep0Edit, 0);
255         writeWepKey(id, wep1Edit, 1);
256         writeWepKey(id, wep2Edit, 2);
257         writeWepKey(id, wep3Edit, 3);
258
259         if (wep0Radio->isEnabled() && wep0Radio->isChecked())
260                 setNetworkParam(id, "wep_tx_keyidx", "0", false);
261         else if (wep1Radio->isEnabled() && wep1Radio->isChecked())
262                 setNetworkParam(id, "wep_tx_keyidx", "1", false);
263         else if (wep2Radio->isEnabled() && wep2Radio->isChecked())
264                 setNetworkParam(id, "wep_tx_keyidx", "2", false);
265         else if (wep3Radio->isEnabled() && wep3Radio->isChecked())
266                 setNetworkParam(id, "wep_tx_keyidx", "3", false);
267
268         if (idstrEdit->isEnabled())
269                 setNetworkParam(id, "id_str",
270                                 idstrEdit->text().toAscii().constData(),
271                                 true);
272
273         if (prioritySpinBox->isEnabled()) {
274                 QString prio;
275                 prio = prio.setNum(prioritySpinBox->value());
276                 setNetworkParam(id, "priority", prio.toAscii().constData(),
277                                 false);
278         }
279
280         snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id);
281         reply_len = sizeof(reply);
282         wpagui->ctrlRequest(cmd, reply, &reply_len);
283         if (strncmp(reply, "OK", 2) != 0) {
284                 QMessageBox::warning(this, "wpa_gui", "Failed to enable "
285                                      "network in wpa_supplicant\n"
286                                      "configuration.");
287                 /* Network was added, so continue anyway */
288         }
289         wpagui->triggerUpdate();
290         wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
291
292         close();
293 }
294
295
296 void NetworkConfig::setWpaGui(WpaGui *_wpagui)
297 {
298         wpagui = _wpagui;
299 }
300
301
302 int NetworkConfig::setNetworkParam(int id, const char *field,
303                                    const char *value, bool quote)
304 {
305         char reply[10], cmd[256];
306         size_t reply_len;
307         snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s",
308                  id, field, quote ? "\"" : "", value, quote ? "\"" : "");
309         reply_len = sizeof(reply);
310         wpagui->ctrlRequest(cmd, reply, &reply_len);
311         return strncmp(reply, "OK", 2) == 0 ? 0 : -1;
312 }
313
314
315 void NetworkConfig::encrChanged(const QString &sel)
316 {
317         wepEnabled(sel.indexOf("WEP") == 0);
318 }
319
320
321 void NetworkConfig::wepEnabled(bool enabled)
322 {
323         wep0Edit->setEnabled(enabled);
324         wep1Edit->setEnabled(enabled);
325         wep2Edit->setEnabled(enabled);
326         wep3Edit->setEnabled(enabled);
327         wep0Radio->setEnabled(enabled);
328         wep1Radio->setEnabled(enabled);
329         wep2Radio->setEnabled(enabled);
330         wep3Radio->setEnabled(enabled);
331 }
332
333
334 void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id)
335 {
336         char buf[10];
337         bool hex;
338         const char *txt, *pos;
339         size_t len;
340
341         if (!edit->isEnabled() || edit->text().isEmpty())
342                 return;
343
344         /*
345          * Assume hex key if only hex characters are present and length matches
346          * with 40, 104, or 128-bit key
347          */
348         txt = edit->text().toAscii().constData();
349         if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
350                 return;
351         len = strlen(txt);
352         if (len == 0)
353                 return;
354         pos = txt;
355         hex = true;
356         while (*pos) {
357                 if (!((*pos >= '0' && *pos <= '9') ||
358                       (*pos >= 'a' && *pos <= 'f') ||
359                       (*pos >= 'A' && *pos <= 'F'))) {
360                         hex = false;
361                         break;
362                 }
363                 pos++;
364         }
365         if (hex && len != 10 && len != 26 && len != 32)
366                 hex = false;
367         snprintf(buf, sizeof(buf), "wep_key%d", id);
368         setNetworkParam(network_id, buf, txt, !hex);
369 }
370
371
372 static int key_value_isset(const char *reply, size_t reply_len)
373 {
374     return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
375 }
376
377
378 void NetworkConfig::paramsFromConfig(int network_id)
379 {
380         int i, res;
381
382         edit_network_id = network_id;
383         getEapCapa();
384
385         char reply[1024], cmd[256], *pos;
386         size_t reply_len;
387
388         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
389         reply_len = sizeof(reply) - 1;
390         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
391             reply_len >= 2 && reply[0] == '"') {
392                 reply[reply_len] = '\0';
393                 pos = strchr(reply + 1, '"');
394                 if (pos)
395                         *pos = '\0';
396                 ssidEdit->setText(reply + 1);
397         }
398
399         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
400         reply_len = sizeof(reply) - 1;
401         int wpa = 0;
402         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
403                 reply[reply_len] = '\0';
404                 if (strstr(reply, "RSN") || strstr(reply, "WPA2"))
405                         wpa = 2;
406                 else if (strstr(reply, "WPA"))
407                         wpa = 1;
408         }
409
410         int auth = AUTH_NONE, encr = 0;
411         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
412         reply_len = sizeof(reply) - 1;
413         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
414                 reply[reply_len] = '\0';
415                 if (strstr(reply, "WPA-EAP"))
416                         auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP;
417                 else if (strstr(reply, "WPA-PSK"))
418                         auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK;
419                 else if (strstr(reply, "IEEE8021X")) {
420                         auth = AUTH_IEEE8021X;
421                         encr = 1;
422                 }
423         }
424
425         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
426         reply_len = sizeof(reply) - 1;
427         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
428                 reply[reply_len] = '\0';
429                 if (strstr(reply, "CCMP") && auth != AUTH_NONE)
430                         encr = 1;
431                 else if (strstr(reply, "TKIP"))
432                         encr = 0;
433                 else if (strstr(reply, "WEP"))
434                         encr = 1;
435                 else
436                         encr = 0;
437         }
438
439         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
440         reply_len = sizeof(reply) - 1;
441         res = wpagui->ctrlRequest(cmd, reply, &reply_len);
442         if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
443                 reply[reply_len] = '\0';
444                 pos = strchr(reply + 1, '"');
445                 if (pos)
446                         *pos = '\0';
447                 pskEdit->setText(reply + 1);
448         } else if (res >= 0 && key_value_isset(reply, reply_len)) {
449                 pskEdit->setText(WPA_GUI_KEY_DATA);
450         }
451
452         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
453         reply_len = sizeof(reply) - 1;
454         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
455             reply_len >= 2 && reply[0] == '"') {
456                 reply[reply_len] = '\0';
457                 pos = strchr(reply + 1, '"');
458                 if (pos)
459                         *pos = '\0';
460                 identityEdit->setText(reply + 1);
461         }
462
463         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
464         reply_len = sizeof(reply) - 1;
465         res = wpagui->ctrlRequest(cmd, reply, &reply_len);
466         if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
467                 reply[reply_len] = '\0';
468                 pos = strchr(reply + 1, '"');
469                 if (pos)
470                         *pos = '\0';
471                 passwordEdit->setText(reply + 1);
472         } else if (res >= 0 && key_value_isset(reply, reply_len)) {
473                 passwordEdit->setText(WPA_GUI_KEY_DATA);
474         }
475
476         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
477         reply_len = sizeof(reply) - 1;
478         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
479             reply_len >= 2 && reply[0] == '"') {
480                 reply[reply_len] = '\0';
481                 pos = strchr(reply + 1, '"');
482                 if (pos)
483                         *pos = '\0';
484                 cacertEdit->setText(reply + 1);
485         }
486
487         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
488         reply_len = sizeof(reply) - 1;
489         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
490             reply_len >= 1) {
491                 reply[reply_len] = '\0';
492                 for (i = 0; i < eapSelect->count(); i++) {
493                         if (eapSelect->itemText(i).compare(reply) == 0) {
494                                 eapSelect->setCurrentIndex(i);
495                                 break;
496                         }
497                 }
498         }
499
500         for (i = 0; i < 4; i++) {
501                 QLineEdit *wepEdit;
502                 switch (i) {
503                 default:
504                 case 0:
505                         wepEdit = wep0Edit;
506                         break;
507                 case 1:
508                         wepEdit = wep1Edit;
509                         break;
510                 case 2:
511                         wepEdit = wep2Edit;
512                         break;
513                 case 3:
514                         wepEdit = wep3Edit;
515                         break;
516                 }
517                 snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d",
518                          network_id, i);
519                 reply_len = sizeof(reply) - 1;
520                 res = wpagui->ctrlRequest(cmd, reply, &reply_len);
521                 if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
522                         reply[reply_len] = '\0';
523                         pos = strchr(reply + 1, '"');
524                         if (pos)
525                                 *pos = '\0';
526                         if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
527                                 encr = 1;
528
529                         wepEdit->setText(reply + 1);
530                 } else if (res >= 0 && key_value_isset(reply, reply_len)) {
531                         if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
532                                 encr = 1;
533                         wepEdit->setText(WPA_GUI_KEY_DATA);
534                 }
535         }
536
537         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
538         reply_len = sizeof(reply) - 1;
539         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1)
540         {
541                 reply[reply_len] = '\0';
542                 switch (atoi(reply)) {
543                 case 0:
544                         wep0Radio->setChecked(true);
545                         break;
546                 case 1:
547                         wep1Radio->setChecked(true);
548                         break;
549                 case 2:
550                         wep2Radio->setChecked(true);
551                         break;
552                 case 3:
553                         wep3Radio->setChecked(true);
554                         break;
555                 }
556         }
557
558         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id);
559         reply_len = sizeof(reply) - 1;
560         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
561             reply_len >= 2 && reply[0] == '"') {
562                 reply[reply_len] = '\0';
563                 pos = strchr(reply + 1, '"');
564                 if (pos)
565                         *pos = '\0';
566                 idstrEdit->setText(reply + 1);
567         }
568
569         snprintf(cmd, sizeof(cmd), "GET_NETWORK %d priority", network_id);
570         reply_len = sizeof(reply) - 1;
571         if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1)
572         {
573                 reply[reply_len] = '\0';
574                 prioritySpinBox->setValue(atoi(reply));
575         }
576
577         authSelect->setCurrentIndex(auth);
578         authChanged(auth);
579         encrSelect->setCurrentIndex(encr);
580         if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
581                 wepEnabled(encr == 1);
582
583         removeButton->setEnabled(true);
584         addButton->setText("Save");
585 }
586
587
588 void NetworkConfig::removeNetwork()
589 {
590         char reply[10], cmd[256];
591         size_t reply_len;
592
593         if (QMessageBox::information(this, "wpa_gui",
594                                      "This will permanently remove the "
595                                      "network\n"
596                                      "from the configuration. Do you really "
597                                      "want\n"
598                                      "to remove this network?", "Yes", "No")
599             != 0)
600                 return;
601
602         snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
603         reply_len = sizeof(reply);
604         wpagui->ctrlRequest(cmd, reply, &reply_len);
605         if (strncmp(reply, "OK", 2) != 0) {
606                 QMessageBox::warning(this, "wpa_gui",
607                                      "Failed to remove network from "
608                                      "wpa_supplicant\n"
609                                      "configuration.");
610         } else {
611                 wpagui->triggerUpdate();
612                 wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
613         }
614
615         close();
616 }
617
618
619 void NetworkConfig::newNetwork()
620 {
621         new_network = true;
622         getEapCapa();
623 }
624
625
626 void NetworkConfig::getEapCapa()
627 {
628         char reply[256];
629         size_t reply_len;
630
631         if (wpagui == NULL)
632                 return;
633
634         reply_len = sizeof(reply) - 1;
635         if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0)
636                 return;
637         reply[reply_len] = '\0';
638
639         QString res(reply);
640         QStringList types = res.split(QChar(' '));
641         eapSelect->insertItems(-1, types);
642 }