summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2012-09-12 11:15:02 -0500
committerDan Williams <dcbw@redhat.com>2012-09-20 10:11:36 -0500
commit80122cf9625949256a7cd0f398340458c8b606d3 (patch)
treea05c89cfec2e692535aac81d0b6de4b4cbdea502
parent997ef39f88d71c2a811ec6b31b330c4604db7909 (diff)
wifi: request new PSK if disconnected during the 4-way handshake
Most often, a disconnect during the 4-way handshake means that the WPA PSK is wrong (though not always). In that case, ask the user for a new password.
-rw-r--r--src/nm-device-wifi.c111
1 files changed, 85 insertions, 26 deletions
diff --git a/src/nm-device-wifi.c b/src/nm-device-wifi.c
index 54261d74..06abfa97 100644
--- a/src/nm-device-wifi.c
+++ b/src/nm-device-wifi.c
@@ -2215,55 +2215,107 @@ link_timeout_cb (gpointer user_data)
}
static gboolean
-handle_8021x_auth_fail (NMDeviceWifi *self, guint32 new_state, guint32 old_state)
+need_new_8021x_secrets (NMDeviceWifi *self,
+ guint32 old_state,
+ const char **setting_name)
{
- NMDevice *device = NM_DEVICE (self);
NMSetting8021x *s_8021x;
NMSettingWirelessSecurity *s_wsec;
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
- NMActRequest *req;
NMConnection *connection;
- const char *setting_name = NULL;
- gboolean handled = FALSE;
- g_return_val_if_fail (new_state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, FALSE);
+ g_assert (setting_name != NULL);
+
+ connection = nm_device_get_connection (NM_DEVICE (self));
+ g_return_val_if_fail (connection != NULL, FALSE);
- /* Only care about ASSOCIATED -> DISCONNECTED transitions since 802.1x stuff
- * happens between the ASSOCIATED and AUTHENTICATED states.
+ /* 802.1x stuff only happens in the supplicant's ASSOCIATED state when it's
+ * attempting to authenticate with the AP.
*/
if (old_state != NM_SUPPLICANT_INTERFACE_STATE_ASSOCIATED)
return FALSE;
- req = nm_device_get_act_request (NM_DEVICE (self));
- g_return_val_if_fail (req != NULL, FALSE);
-
- connection = nm_act_request_get_connection (req);
- g_return_val_if_fail (connection != NULL, FALSE);
-
/* If it's an 802.1x or LEAP connection with "always ask"/unsaved secrets
* then we need to ask again because it might be an OTP token and the PIN
* may have changed.
*/
- s_8021x = nm_connection_get_setting_802_1x (connection);
- s_wsec = nm_connection_get_setting_wireless_security (connection);
+ s_8021x = nm_connection_get_setting_802_1x (connection);
if (s_8021x) {
nm_setting_get_secret_flags (NM_SETTING (s_8021x),
NM_SETTING_802_1X_PASSWORD,
&secret_flags,
NULL);
- setting_name = NM_SETTING_802_1X_SETTING_NAME;
- } else if (s_wsec) {
+ if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)
+ *setting_name = NM_SETTING_802_1X_SETTING_NAME;
+ return *setting_name ? TRUE : FALSE;
+ }
+
+ s_wsec = nm_connection_get_setting_wireless_security (connection);
+ if (s_wsec) {
nm_setting_get_secret_flags (NM_SETTING (s_wsec),
NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD,
&secret_flags,
NULL);
- setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
+ if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)
+ *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
+ return *setting_name ? TRUE : FALSE;
}
- if (setting_name && (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED)) {
- NMSettingsGetSecretsFlags flags = NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION
- | NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW;
+ /* Not a LEAP or 802.1x connection */
+ return FALSE;
+}
+
+static gboolean
+need_new_wpa_psk (NMDeviceWifi *self,
+ guint32 old_state,
+ const char **setting_name)
+{
+ NMSettingWirelessSecurity *s_wsec;
+ NMConnection *connection;
+ const char *key_mgmt = NULL;
+
+ g_assert (setting_name != NULL);
+
+ connection = nm_device_get_connection (NM_DEVICE (self));
+ g_return_val_if_fail (connection != NULL, FALSE);
+
+ /* A bad PSK will cause the supplicant to disconnect during the 4-way handshake */
+ if (old_state != NM_SUPPLICANT_INTERFACE_STATE_4WAY_HANDSHAKE)
+ return FALSE;
+
+ s_wsec = nm_connection_get_setting_wireless_security (connection);
+ if (s_wsec)
+ key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
+
+ if (g_strcmp0 (key_mgmt, "wpa-psk") == 0) {
+ *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
+ return TRUE;
+ }
+
+ /* Not a WPA-PSK connection */
+ return FALSE;
+}
+
+static gboolean
+handle_8021x_or_psk_auth_fail (NMDeviceWifi *self, guint32 new_state, guint32 old_state)
+{
+ NMDevice *device = NM_DEVICE (self);
+ NMActRequest *req;
+ NMConnection *connection;
+ const char *setting_name = NULL;
+ gboolean handled = FALSE;
+
+ g_return_val_if_fail (new_state == NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED, FALSE);
+
+ req = nm_device_get_act_request (NM_DEVICE (self));
+ g_return_val_if_fail (req != NULL, FALSE);
+
+ connection = nm_act_request_get_connection (req);
+ g_assert (connection);
+
+ if ( need_new_8021x_secrets (self, old_state, &setting_name)
+ || need_new_wpa_psk (self, old_state, &setting_name)) {
nm_connection_clear_secrets (connection);
@@ -2273,7 +2325,13 @@ handle_8021x_auth_fail (NMDeviceWifi *self, guint32 new_state, guint32 old_state
cleanup_association_attempt (self, TRUE);
nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT);
- nm_act_request_get_secrets (req, setting_name, flags, NULL, wifi_secrets_cb, self);
+ nm_act_request_get_secrets (req,
+ setting_name,
+ NM_SETTINGS_GET_SECRETS_FLAG_ALLOW_INTERACTION
+ | NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW,
+ NULL,
+ wifi_secrets_cb,
+ self);
handled = TRUE;
}
@@ -2352,12 +2410,13 @@ supplicant_iface_state_cb (NMSupplicantInterface *iface,
break;
case NM_SUPPLICANT_INTERFACE_STATE_DISCONNECTED:
if ((devstate == NM_DEVICE_STATE_ACTIVATED) || nm_device_is_activating (device)) {
- /* Disconnect of an 802.1x/LEAP connection during authentication
- * means secrets might be wrong. Not always the case, but until we
+ /* Disconnect of an 802.1x/LEAP connection during authentication,
+ * or disconnect of a WPA-PSK connection during the 4-way handshake,
+ * often means secrets are wrong. Not always the case, but until we
* have more information from wpa_supplicant about why the
* disconnect happened this is the best we can do.
*/
- if (handle_8021x_auth_fail (self, new_state, old_state))
+ if (handle_8021x_or_psk_auth_fail (self, new_state, old_state))
break;
}