1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /*
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the
15 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16 * Boston, MA 02110-1301 USA.
17 *
18 * (C) Copyright 2011 Red Hat, Inc.
19 */
20
21 #include <config.h>
22 #include <string.h>
23 #include <stdlib.h>
24
25 #include "nm-wifi-ap-utils.h"
26
27 static gboolean
28 verify_no_wep (NMSettingWirelessSecurity *s_wsec, const char *tag, GError **error)
29 {
30 if ( nm_setting_wireless_security_get_wep_key (s_wsec, 0)
31 || nm_setting_wireless_security_get_wep_key (s_wsec, 1)
32 || nm_setting_wireless_security_get_wep_key (s_wsec, 2)
33 || nm_setting_wireless_security_get_wep_key (s_wsec, 3)
34 || nm_setting_wireless_security_get_wep_tx_keyidx (s_wsec)
35 || nm_setting_wireless_security_get_wep_key_type (s_wsec)) {
36 /* Dynamic WEP cannot have any WEP keys set */
37 g_set_error (error,
38 NM_SETTING_WIRELESS_SECURITY_ERROR,
39 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
40 "%s is incompatible with static WEP keys", tag);
41 return FALSE;
42 }
43
44 return TRUE;
45 }
46
47 static gboolean
48 verify_leap (NMSettingWirelessSecurity *s_wsec,
49 NMSetting8021x *s_8021x,
50 gboolean adhoc,
51 GError **error)
52 {
53 const char *key_mgmt, *auth_alg, *leap_username;
54
55 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
56 auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
57 leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
58
59 /* One (or both) of two things indicates we want LEAP:
60 * 1) auth_alg == 'leap'
61 * 2) valid leap_username
62 *
63 * LEAP always requires a LEAP username.
64 */
65
66 if (auth_alg) {
67 if (!strcmp (auth_alg, "leap")) {
68 /* LEAP authentication requires at least a LEAP username */
69 if (!leap_username) {
70 g_set_error_literal (error,
71 NM_SETTING_WIRELESS_SECURITY_ERROR,
72 NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME,
73 "LEAP requires a LEAP username");
74 return FALSE;
75 }
76 } else if (leap_username) {
77 /* Leap username requires 'leap' auth */
78 g_set_error_literal (error,
79 NM_SETTING_WIRELESS_SECURITY_ERROR,
80 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
81 "LEAP requires 'leap' authentication");
82 return FALSE;
83 }
84 }
85
86 if (leap_username) {
87 if (key_mgmt && strcmp (key_mgmt, "ieee8021x")) {
88 /* LEAP requires ieee8021x key management */
89 g_set_error_literal (error,
90 NM_SETTING_WIRELESS_SECURITY_ERROR,
91 NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_802_1X,
92 "LEAP requires IEEE 802.1x key management");
93 return FALSE;
94 }
95 }
96
97 /* At this point if auth_alg is set it must be 'leap', and if key_mgmt
98 * is set it must be 'ieee8021x'.
99 */
100 if (leap_username) {
101 if (auth_alg)
102 g_assert (strcmp (auth_alg, "leap") == 0);
103 if (key_mgmt)
104 g_assert (strcmp (key_mgmt, "ieee8021x") == 0);
105
106 if (adhoc) {
107 g_set_error_literal (error,
108 NM_SETTING_WIRELESS_SECURITY_ERROR,
109 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
110 "LEAP incompatible with Ad-Hoc mode");
111 return FALSE;
112 }
113
114 if (!verify_no_wep (s_wsec, "LEAP", error))
115 return FALSE;
116
117 if (s_8021x) {
118 g_set_error_literal (error,
119 NM_SETTING_WIRELESS_SECURITY_ERROR,
120 NM_SETTING_WIRELESS_SECURITY_ERROR_LEAP_REQUIRES_USERNAME,
121 "LEAP incompatible with 802.1x setting");
122 return FALSE;
123 }
124 }
125
126 return TRUE;
127 }
128
129 static gboolean
130 verify_no_wpa (NMSettingWirelessSecurity *s_wsec,
131 const char *tag,
132 GError **error)
133 {
134 const char *key_mgmt;
135 int n, i;
136
137 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
138 if (key_mgmt && !strncmp (key_mgmt, "wpa", 3)) {
139 g_set_error (error,
140 NM_SETTING_WIRELESS_SECURITY_ERROR,
141 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
142 "%s incompatible with any WPA key management", tag);
143 return FALSE;
144 }
145
146 if (nm_setting_wireless_security_get_num_protos (s_wsec)) {
147 g_set_error (error,
148 NM_SETTING_WIRELESS_SECURITY_ERROR,
149 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
150 "%s incompatible with any 'proto' setting", tag);
151 return FALSE;
152 }
153
154 n = nm_setting_wireless_security_get_num_pairwise (s_wsec);
155 for (i = 0; i < n; i++) {
156 const char *pw;
157
158 pw = nm_setting_wireless_security_get_pairwise (s_wsec, i);
159 if (!strcmp (pw, "tkip") || !strcmp (pw, "ccmp")) {
160 g_set_error (error,
161 NM_SETTING_WIRELESS_SECURITY_ERROR,
162 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
163 "%s is incompatible with WPA pairwise ciphers", tag);
164 return FALSE;
165 }
166 }
167
168 n = nm_setting_wireless_security_get_num_groups (s_wsec);
169 for (i = 0; i < n; i++) {
170 const char *gr;
171
172 gr = nm_setting_wireless_security_get_group (s_wsec, i);
173 if (strcmp (gr, "wep40") && strcmp (gr, "wep104")) {
174 g_set_error (error,
175 NM_SETTING_WIRELESS_SECURITY_ERROR,
176 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
177 "%s is incompatible with WPA group ciphers", tag);
178 return FALSE;
179 }
180 }
181
182 if (nm_setting_wireless_security_get_psk (s_wsec)) {
183 g_set_error (error,
184 NM_SETTING_WIRELESS_SECURITY_ERROR,
185 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
186 "%s is incompatible with a WPA Pre-Shared Key", tag);
187 return FALSE;
188 }
189
190 return TRUE;
191 }
192
193 static gboolean
194 verify_dynamic_wep (NMSettingWirelessSecurity *s_wsec,
195 NMSetting8021x *s_8021x,
196 gboolean adhoc,
197 GError **error)
198 {
199 const char *key_mgmt, *auth_alg, *leap_username;
200
201 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
202 auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
203 leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
204
205 g_return_val_if_fail (leap_username == NULL, TRUE);
206
207 if (key_mgmt) {
208 if (!strcmp (key_mgmt, "ieee8021x")) {
209 if (!s_8021x) {
210 /* 802.1x key management requires an 802.1x setting */
211 g_set_error_literal (error,
212 NM_SETTING_WIRELESS_SECURITY_ERROR,
213 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
214 "Dynamic WEP requires an 802.1x setting");
215 return FALSE;
216 }
217
218 if (auth_alg && strcmp (auth_alg, "open")) {
219 /* 802.1x key management must use "open" authentication */
220 g_set_error_literal (error,
221 NM_SETTING_WIRELESS_SECURITY_ERROR,
222 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
223 "Dynamic WEP requires 'open' authentication");
224 return FALSE;
225 }
226
227 /* Dynamic WEP incompatible with anything static WEP related */
228 if (!verify_no_wep (s_wsec, "Dynamic WEP", error))
229 return FALSE;
230 } else if (!strcmp (key_mgmt, "none")) {
231 if (s_8021x) {
232 /* 802.1x setting requires 802.1x key management */
233 g_set_error_literal (error,
234 NM_SETTING_WIRELESS_SECURITY_ERROR,
235 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
236 "Dynamic WEP requires 'ieee8021x' key management");
237 return FALSE;
238 }
239 }
240 } else if (s_8021x) {
241 /* 802.1x setting incompatible with anything but 'open' auth */
242 if (auth_alg && strcmp (auth_alg, "open")) {
243 /* 802.1x key management must use "open" authentication */
244 g_set_error_literal (error,
245 NM_SETTING_WIRELESS_SECURITY_ERROR,
246 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
247 "Dynamic WEP requires 'open' authentication");
248 return FALSE;
249 }
250
251 /* Dynamic WEP incompatible with anything static WEP related */
252 if (!verify_no_wep (s_wsec, "Dynamic WEP", error))
253 return FALSE;
254 }
255
256 return TRUE;
257 }
258
259 static gboolean
260 verify_wpa_psk (NMSettingWirelessSecurity *s_wsec,
261 NMSetting8021x *s_8021x,
262 gboolean adhoc,
263 guint32 wpa_flags,
264 guint32 rsn_flags,
265 GError **error)
266 {
267 const char *key_mgmt, *auth_alg, *tmp;
268 int n;
269
270 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
271 auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
272
(1) Event cond_true: |
Condition "key_mgmt", taking true branch |
273 if (key_mgmt) {
(2) Event cond_true: |
Condition "!__coverity_strcmp(key_mgmt, "wpa-psk")", taking true branch |
274 if (!strcmp (key_mgmt, "wpa-psk") || !strcmp (key_mgmt, "wpa-none")) {
(3) Event cond_false: |
Condition "s_8021x", taking false branch |
275 if (s_8021x) {
276 g_set_error_literal (error,
277 NM_SETTING_WIRELESS_SECURITY_ERROR,
278 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
279 "WPA-PSK incompatible with 802.1x");
280 return FALSE;
(4) Event if_end: |
End of if statement |
281 }
282
(5) Event cond_true: |
Condition "auth_alg", taking true branch |
(6) Event cond_false: |
Condition "__coverity_strcmp(auth_alg, "open")", taking false branch |
283 if (auth_alg && strcmp (auth_alg, "open")) {
284 /* WPA must use "open" authentication */
285 g_set_error_literal (error,
286 NM_SETTING_WIRELESS_SECURITY_ERROR,
287 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
288 "WPA-PSK requires 'open' authentication");
289 return FALSE;
(7) Event if_end: |
End of if statement |
290 }
291 }
292
(8) Event cond_true: |
Condition "!__coverity_strcmp(key_mgmt, "wpa-none")", taking true branch |
293 if (!strcmp (key_mgmt, "wpa-none")) {
(9) Event cond_false: |
Condition "!adhoc", taking false branch |
294 if (!adhoc) {
295 g_set_error_literal (error,
296 NM_SETTING_WIRELESS_SECURITY_ERROR,
297 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
298 "WPA Ad-Hoc requires an Ad-Hoc mode AP");
299 return FALSE;
(10) Event if_end: |
End of if statement |
300 }
301
302 /* Ad-Hoc WPA requires 'wpa' proto, 'none' pairwise, and 'tkip' group */
303 n = nm_setting_wireless_security_get_num_protos (s_wsec);
(11) Event cond_true: |
Condition "n > 0", taking true branch |
304 tmp = (n > 0) ? nm_setting_wireless_security_get_proto (s_wsec, 0) : NULL;
(12) Event cond_false: |
Condition "n > 1", taking false branch |
(13) Event cond_false: |
Condition "__coverity_strcmp(tmp, "wpa")", taking false branch |
305 if (n > 1 || strcmp (tmp, "wpa")) {
306 g_set_error_literal (error,
307 NM_SETTING_WIRELESS_SECURITY_ERROR,
308 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
309 "WPA Ad-Hoc requires 'wpa' proto");
310 return FALSE;
(14) Event if_end: |
End of if statement |
311 }
312
313 n = nm_setting_wireless_security_get_num_pairwise (s_wsec);
(15) Event cond_false: |
Condition "n > 0", taking false branch |
(16) Event assign_zero: |
Assigning: "tmp" = "NULL". |
Also see events: |
[var_deref_model] |
314 tmp = (n > 0) ? nm_setting_wireless_security_get_pairwise (s_wsec, 0) : NULL;
(17) Event cond_false: |
Condition "n > 1", taking false branch |
(18) Event var_deref_model: |
Passing null pointer "tmp" to function "__coverity_strcmp(char const *, char const *)", which dereferences it. |
Also see events: |
[assign_zero] |
315 if (n > 1 || strcmp (tmp, "none")) {
316 g_set_error_literal (error,
317 NM_SETTING_WIRELESS_SECURITY_ERROR,
318 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
319 "WPA Ad-Hoc requires 'none' pairwise cipher");
320 return FALSE;
321 }
322
323 n = nm_setting_wireless_security_get_num_groups (s_wsec);
324 tmp = (n > 0) ? nm_setting_wireless_security_get_group (s_wsec, 0) : NULL;
325 if (n > 1 || strcmp (tmp, "tkip")) {
326 g_set_error_literal (error,
327 NM_SETTING_WIRELESS_SECURITY_ERROR,
328 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
329 "WPA Ad-Hoc requires 'tkip' group cipher");
330 return FALSE;
331 }
332 }
333
334 if (!strcmp (key_mgmt, "wpa-psk")) {
335 /* Make sure the AP's capabilities support WPA-PSK */
336 if ( !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
337 && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
338 g_set_error_literal (error,
339 NM_SETTING_WIRELESS_SECURITY_ERROR,
340 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
341 "AP does not support PSK but setting requires it");
342 return FALSE;
343 }
344 }
345 }
346
347 return TRUE;
348 }
349
350 static gboolean
351 verify_wpa_eap (NMSettingWirelessSecurity *s_wsec,
352 NMSetting8021x *s_8021x,
353 guint32 wpa_flags,
354 guint32 rsn_flags,
355 GError **error)
356 {
357 const char *key_mgmt, *auth_alg;
358 gboolean is_wpa_eap = FALSE;
359
360 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
361 auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
362
363 if (key_mgmt) {
364 if (!strcmp (key_mgmt, "wpa-eap")) {
365 if (!s_8021x) {
366 g_set_error_literal (error,
367 NM_SETTING_WIRELESS_SECURITY_ERROR,
368 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
369 "WPA-EAP requires an 802.1x setting");
370 return FALSE;
371 }
372
373 if (auth_alg && strcmp (auth_alg, "open")) {
374 /* WPA must use "open" authentication */
375 g_set_error_literal (error,
376 NM_SETTING_WIRELESS_SECURITY_ERROR,
377 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
378 "WPA-EAP requires 'open' authentication");
379 return FALSE;
380 }
381
382 is_wpa_eap = TRUE;
383 } else if (s_8021x) {
384 g_set_error_literal (error,
385 NM_SETTING_WIRELESS_SECURITY_ERROR,
386 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
387 "Setting requires 802.1x but does not use 'wpa-eap' key management");
388 return FALSE;
389 }
390 }
391
392 if (is_wpa_eap || s_8021x) {
393 /* Make sure the AP's capabilities support WPA-EAP */
394 if ( !(wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)
395 && !(rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_802_1X)) {
396 g_set_error_literal (error,
397 NM_SETTING_WIRELESS_SECURITY_ERROR,
398 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
399 "AP does not support 802.1x but setting requires it");
400 return FALSE;
401 }
402 }
403
404 return TRUE;
405 }
406
407 static gboolean
408 verify_adhoc (NMSettingWirelessSecurity *s_wsec,
409 NMSetting8021x *s_8021x,
410 gboolean adhoc,
411 GError **error)
412 {
413 const char *key_mgmt = NULL, *leap_username = NULL, *auth_alg = NULL;
414
415 if (s_wsec) {
416 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
417 auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
418 leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
419 }
420
421 if (adhoc) {
422 if (key_mgmt && strcmp (key_mgmt, "wpa-none") && strcmp (key_mgmt, "none")) {
423 g_set_error_literal (error,
424 NM_SETTING_WIRELESS_SECURITY_ERROR,
425 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
426 "AP mode is Ad-Hoc but setting requires Infrastructure security");
427 return FALSE;
428 }
429
430 if (s_8021x) {
431 g_set_error_literal (error,
432 NM_SETTING_WIRELESS_SECURITY_ERROR,
433 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
434 "Ad-Hoc mode incompatible with 802.1x security");
435 return FALSE;
436 }
437
438 if (leap_username) {
439 g_set_error_literal (error,
440 NM_SETTING_WIRELESS_SECURITY_ERROR,
441 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
442 "Ad-Hoc mode incompatible with LEAP security");
443 return FALSE;
444 }
445
446 if (auth_alg && strcmp (auth_alg, "open")) {
447 g_set_error_literal (error,
448 NM_SETTING_WIRELESS_SECURITY_ERROR,
449 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
450 "Ad-Hoc mode requires 'open' authentication");
451 return FALSE;
452 }
453 } else {
454 if (key_mgmt && !strcmp (key_mgmt, "wpa-none")) {
455 g_set_error_literal (error,
456 NM_SETTING_WIRELESS_SECURITY_ERROR,
457 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
458 "AP mode is Infrastructure but setting requires Ad-Hoc security");
459 return FALSE;
460 }
461 }
462
463 return TRUE;
464 }
465
466 gboolean
467 nm_ap_utils_complete_connection (const GByteArray *ap_ssid,
468 const guint8 ap_bssid[ETH_ALEN],
469 NM80211Mode ap_mode,
470 guint32 ap_flags,
471 guint32 ap_wpa_flags,
472 guint32 ap_rsn_flags,
473 NMConnection *connection,
474 gboolean lock_bssid,
475 GError **error)
476 {
477 NMSettingWireless *s_wifi;
478 NMSettingWirelessSecurity *s_wsec;
479 NMSetting8021x *s_8021x;
480 const GByteArray *ssid;
481 const char *mode, *key_mgmt, *auth_alg, *leap_username;
482 gboolean adhoc = FALSE;
483
484 s_wifi = nm_connection_get_setting_wireless (connection);
485 g_assert (s_wifi);
486 s_wsec = nm_connection_get_setting_wireless_security (connection);
487 s_8021x = nm_connection_get_setting_802_1x (connection);
488
489 /* Fill in missing SSID */
490 ssid = nm_setting_wireless_get_ssid (s_wifi);
491 if (!ssid)
492 g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_SSID, ap_ssid, NULL);
493 else if ( ssid->len != ap_ssid->len
494 || memcmp (ssid->data, ap_ssid->data, ssid->len)) {
495 g_set_error_literal (error,
496 NM_SETTING_WIRELESS_ERROR,
497 NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
498 "Setting SSID did not match AP SSID");
499 return FALSE;
500 }
501
502 if (lock_bssid && !nm_setting_wireless_get_bssid (s_wifi)) {
503 GByteArray *bssid;
504
505 bssid = g_byte_array_sized_new (ETH_ALEN);
506 g_byte_array_append (bssid, ap_bssid, ETH_ALEN);
507 g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_BSSID, bssid, NULL);
508 g_byte_array_free (bssid, TRUE);
509 }
510
511 /* And mode */
512 mode = nm_setting_wireless_get_mode (s_wifi);
513 if (mode) {
514 gboolean valid = FALSE;
515
516 /* Make sure the supplied mode matches the AP's */
517 if ( !strcmp (mode, NM_SETTING_WIRELESS_MODE_INFRA)
518 || !strcmp (mode, NM_SETTING_WIRELESS_MODE_AP)) {
519 if (ap_mode == NM_802_11_MODE_INFRA)
520 valid = TRUE;
521 } else if (!strcmp (mode, NM_SETTING_WIRELESS_MODE_ADHOC)) {
522 if (ap_mode == NM_802_11_MODE_ADHOC)
523 valid = TRUE;
524 adhoc = TRUE;
525 }
526
527 if (valid == FALSE) {
528 g_set_error (error,
529 NM_SETTING_WIRELESS_ERROR,
530 NM_SETTING_WIRELESS_ERROR_INVALID_PROPERTY,
531 NM_SETTING_WIRELESS_MODE);
532 return FALSE;
533 }
534 } else {
535 mode = NM_SETTING_WIRELESS_MODE_INFRA;
536 if (ap_mode == NM_802_11_MODE_ADHOC) {
537 mode = NM_SETTING_WIRELESS_MODE_ADHOC;
538 adhoc = TRUE;
539 }
540 g_object_set (G_OBJECT (s_wifi), NM_SETTING_WIRELESS_MODE, mode, NULL);
541 }
542
543 /* Security */
544
545 /* Open */
546 if ( !(ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
547 && (ap_wpa_flags == NM_802_11_AP_SEC_NONE)
548 && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) {
549 /* Make sure the connection doesn't specify security */
550 if (s_wsec || s_8021x) {
551 g_set_error_literal (error,
552 NM_SETTING_WIRELESS_SECURITY_ERROR,
553 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
554 "AP is unencrypted but setting specifies security");
555 return FALSE;
556 }
557 return TRUE;
558 }
559
560 /* Everything else requires security */
561 if (!s_wsec) {
562 s_wsec = (NMSettingWirelessSecurity *) nm_setting_wireless_security_new ();
563 nm_connection_add_setting (connection, NM_SETTING (s_wsec));
564 }
565
566 key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
567 auth_alg = nm_setting_wireless_security_get_auth_alg (s_wsec);
568 leap_username = nm_setting_wireless_security_get_leap_username (s_wsec);
569
570 /* Ad-Hoc checks */
571 if (!verify_adhoc (s_wsec, s_8021x, adhoc, error))
572 return FALSE;
573
574 /* Static WEP, Dynamic WEP, or LEAP */
575 if ( (ap_flags & NM_802_11_AP_FLAGS_PRIVACY)
576 && (ap_wpa_flags == NM_802_11_AP_SEC_NONE)
577 && (ap_rsn_flags == NM_802_11_AP_SEC_NONE)) {
578 const char *tag = "WEP";
579 gboolean is_dynamic_wep = FALSE;
580
581 if (!verify_leap (s_wsec, s_8021x, adhoc, error))
582 return FALSE;
583
584 if (leap_username) {
585 tag = "LEAP";
586 } else {
587 /* Static or Dynamic WEP */
588 if (!verify_dynamic_wep (s_wsec, s_8021x, adhoc, error))
589 return FALSE;
590
591 if (s_8021x || (key_mgmt && !strcmp (key_mgmt, "ieee8021x"))) {
592 is_dynamic_wep = TRUE;
593 tag = "Dynamic WEP";
594 }
595 }
596
597 /* Nothing WPA-related can be set */
598 if (!verify_no_wpa (s_wsec, tag, error))
599 return FALSE;
600
601 if (leap_username) {
602 /* LEAP */
603 g_object_set (s_wsec,
604 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
605 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "leap",
606 NULL);
607 } else if (is_dynamic_wep) {
608 /* Dynamic WEP */
609 g_object_set (s_wsec,
610 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "ieee8021x",
611 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
612 NULL);
613
614 if (s_8021x) {
615 /* Dynamic WEP requires a valid 802.1x setting since we can't
616 * autocomplete 802.1x.
617 */
618 if (!nm_setting_verify (NM_SETTING (s_8021x), NULL, error))
619 return FALSE;
620 }
621 } else {
622 /* Static WEP */
623 g_object_set (s_wsec,
624 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "none",
625 NULL);
626 }
627
628 return TRUE;
629 }
630
631 /* WPA/RSN */
632 g_assert (ap_wpa_flags || ap_rsn_flags);
633
634 /* Ensure key management is valid for WPA */
635 if ((key_mgmt && !strcmp (key_mgmt, "ieee8021x")) || leap_username) {
636 g_set_error_literal (error,
637 NM_SETTING_WIRELESS_SECURITY_ERROR,
638 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
639 "WPA incompatible with non-EAP (original) LEAP or Dynamic WEP");
640 return FALSE;
641 }
642
643 /* 'shared' auth incompatible with any type of WPA */
644 if (auth_alg && strcmp (auth_alg, "open")) {
645 g_set_error_literal (error,
646 NM_SETTING_WIRELESS_SECURITY_ERROR,
647 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
648 "WPA incompatible with Shared Key authentication");
649 return FALSE;
650 }
651
652 if (!verify_no_wep (s_wsec, "WPA", error))
653 return FALSE;
654
655 if (!verify_wpa_psk (s_wsec, s_8021x, adhoc, ap_wpa_flags, ap_rsn_flags, error))
656 return FALSE;
657
658 if (!adhoc && !verify_wpa_eap (s_wsec, s_8021x, ap_wpa_flags, ap_rsn_flags, error))
659 return FALSE;
660
661 if (adhoc) {
662 g_object_set (s_wsec, NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-none", NULL);
663 /* Ad-Hoc does not support RSN/WPA2 */
664 nm_setting_wireless_security_add_proto (s_wsec, "wpa");
665 nm_setting_wireless_security_add_pairwise (s_wsec, "none");
666 nm_setting_wireless_security_add_group (s_wsec, "tkip");
667 } else if (s_8021x) {
668 g_object_set (s_wsec,
669 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-eap",
670 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
671 NULL);
672 /* Leave proto/pairwise/group as client set them; if they are unset the
673 * supplicant will figure out the best combination at connect time.
674 */
675
676 /* 802.1x also requires the client to completely fill in the 8021x
677 * setting. Since there's so much configuration required for it, there's
678 * no way it can be automatically completed.
679 */
680 } else if ( (key_mgmt && !strcmp (key_mgmt, "wpa-psk"))
681 || (ap_wpa_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)
682 || (ap_rsn_flags & NM_802_11_AP_SEC_KEY_MGMT_PSK)) {
683 g_object_set (s_wsec,
684 NM_SETTING_WIRELESS_SECURITY_KEY_MGMT, "wpa-psk",
685 NM_SETTING_WIRELESS_SECURITY_AUTH_ALG, "open",
686 NULL);
687 /* Leave proto/pairwise/group as client set them; if they are unset the
688 * supplicant will figure out the best combination at connect time.
689 */
690 } else {
691 g_set_error_literal (error,
692 NM_SETTING_WIRELESS_SECURITY_ERROR,
693 NM_SETTING_WIRELESS_SECURITY_ERROR_INVALID_PROPERTY,
694 "Failed to determine AP security information");
695 return FALSE;
696 }
697
698 return TRUE;
699 }
700
701 guint32
702 nm_ap_utils_level_to_quality (gint val)
703 {
704 if (val < 0) {
705 /* Assume dBm already; rough conversion: best = -40, worst = -100 */
706 val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */
707 val = 100 - (int) ((100.0 * (double) val) / 60.0);
708 } else if (val > 110 && val < 256) {
709 /* assume old-style WEXT 8-bit unsigned signal level */
710 val -= 256; /* subtract 256 to convert to dBm */
711 val = abs (CLAMP (val, -100, -40) + 40); /* normalize to 0 */
712 val = 100 - (int) ((100.0 * (double) val) / 60.0);
713 } else {
714 /* Assume signal is a "quality" percentage */
715 val = CLAMP (val, 0, 100);
716 }
717 g_assert (val >= 0);
718
719 return (guint32) val;
720 }
721
722