diff options
Diffstat (limited to 'src/devices/wifi/nm-device-iwd.c')
-rw-r--r-- | src/devices/wifi/nm-device-iwd.c | 337 |
1 files changed, 108 insertions, 229 deletions
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c index 022c37cbb8..75e9977b02 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -75,6 +75,7 @@ typedef struct { GCancellable * cancellable; NMDeviceWifiCapabilities capabilities; NMActRequestGetSecretsCallId *wifi_secrets_id; + GDBusMethodInvocation *secrets_request; guint periodic_scan_id; bool enabled:1; bool can_scan:1; @@ -387,10 +388,30 @@ send_disconnect (NMDeviceIwd *self) } static void +wifi_secrets_cancel (NMDeviceIwd *self) +{ + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + + if (priv->wifi_secrets_id) + nm_act_request_cancel_secrets (NULL, priv->wifi_secrets_id); + nm_assert (!priv->wifi_secrets_id); + + if (priv->secrets_request) { + g_dbus_method_invocation_return_error_literal (priv->secrets_request, NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "NM secrets request cancelled"); + priv->secrets_request = NULL; + } + +} + +static void cleanup_association_attempt (NMDeviceIwd *self, gboolean disconnect) { NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + wifi_secrets_cancel (self); + set_current_ap (self, NULL, TRUE); if (disconnect && priv->dbus_obj) @@ -1020,13 +1041,15 @@ scanning_prohibited (NMDeviceIwd *self, gboolean periodic) static void wifi_secrets_cb (NMActRequest *req, NMActRequestGetSecretsCallId *call_id, - NMSettingsConnection *connection, + NMSettingsConnection *s_connection, GError *error, gpointer user_data) { NMDevice *device = user_data; NMDeviceIwd *self = user_data; NMDeviceIwdPrivate *priv; + NMSettingWirelessSecurity *s_wireless_sec; + const gchar *psk; g_return_if_fail (NM_IS_DEVICE_IWD (self)); g_return_if_fail (NM_IS_ACT_REQUEST (req)); @@ -1040,28 +1063,50 @@ wifi_secrets_cb (NMActRequest *req, if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; + g_return_if_fail (priv->secrets_request); g_return_if_fail (req == nm_device_get_act_request (device)); - g_return_if_fail (nm_device_get_state (device) == NM_DEVICE_STATE_NEED_AUTH); - g_return_if_fail (nm_act_request_get_settings_connection (req) == connection); + g_return_if_fail (nm_act_request_get_settings_connection (req) == s_connection); + + if (nm_device_get_state (device) != NM_DEVICE_STATE_NEED_AUTH) + goto secrets_error; if (error) { _LOGW (LOGD_WIFI, "%s", error->message); + goto secrets_error; + } - nm_device_state_changed (device, - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } else - nm_device_activate_schedule_stage1_device_prepare (device); -} + s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req)); + if (!s_wireless_sec) + goto secrets_error; -static void -wifi_secrets_cancel (NMDeviceIwd *self) -{ - NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); + psk = nm_setting_wireless_security_get_psk (s_wireless_sec); + if (!psk) + goto secrets_error; - if (priv->wifi_secrets_id) - nm_act_request_cancel_secrets (NULL, priv->wifi_secrets_id); - nm_assert (!priv->wifi_secrets_id); + _LOGD (LOGD_DEVICE | LOGD_WIFI, + "Returning a new PSK to the IWD Agent"); + + g_dbus_method_invocation_return_value (priv->secrets_request, + g_variant_new ("(s)", psk)); + priv->secrets_request = NULL; + + /* Change state back to what it was before NEED_AUTH */ + nm_device_state_changed (device, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE); + return; + +secrets_error: + if (priv->secrets_request) { + g_dbus_method_invocation_return_error_literal (priv->secrets_request, NM_DEVICE_ERROR, + NM_DEVICE_ERROR_INVALID_CONNECTION, + "NM secrets request failed"); + priv->secrets_request = NULL; + } + + nm_device_state_changed (device, + NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); + + cleanup_association_attempt (self, TRUE); } static void @@ -1084,130 +1129,6 @@ wifi_secrets_get_secrets (NMDeviceIwd *self, NULL, wifi_secrets_cb, self); - g_return_if_fail (priv->wifi_secrets_id); -} - -static gboolean -need_new_8021x_secrets (NMDeviceIwd *self, - const char **setting_name) -{ - NMSetting8021x *s_8021x; - NMSettingWirelessSecurity *s_wsec; - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - NMConnection *connection; - - g_assert (setting_name != NULL); - - connection = nm_device_get_applied_connection (NM_DEVICE (self)); - 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); - if (s_8021x) { - if (!nm_setting_get_secret_flags (NM_SETTING (s_8021x), - NM_SETTING_802_1X_PASSWORD, - &secret_flags, - NULL)) - g_assert_not_reached (); - 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) { - if (!nm_setting_get_secret_flags (NM_SETTING (s_wsec), - NM_SETTING_WIRELESS_SECURITY_LEAP_PASSWORD, - &secret_flags, - NULL)) - g_assert_not_reached (); - if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED) - *setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME; - return *setting_name ? TRUE : FALSE; - } - - /* Not a LEAP or 802.1x connection */ - return FALSE; -} - -static gboolean -need_new_wpa_psk (NMDeviceIwd *self, - const char **setting_name) -{ - NMSettingWirelessSecurity *s_wsec; - NMConnection *connection; - const char *key_mgmt = NULL; - - g_assert (setting_name != NULL); - - connection = nm_device_get_applied_connection (NM_DEVICE (self)); - g_return_val_if_fail (connection != NULL, 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) { - /* We don't have any data from IWD about the disconnect - * reason or association state when the disconnect happened - * so just assume it was a bad password. - */ - *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 (NMDeviceIwd *self) -{ - NMDevice *device = NM_DEVICE (self); - NMActRequest *req; - const char *setting_name = NULL; - gboolean handled = FALSE; - NMConnection *connection; - - req = nm_device_get_act_request (device); - g_return_val_if_fail (req != NULL, FALSE); - - /* If this is an IWD Known Network, even if the failure was caused by bad secrets, - * IWD won't ask our agent for new secrets until we call ForgetNetwork. For 8021x - * this is not a good idea since the IWD network config file is assumed to be - * provisioned by the system admin and the admin needs to intervene anyway. For - * PSK we may want to do this here (TODO). - */ - connection = nm_act_request_get_applied_connection (req); - if (is_connection_known_network (connection)) { - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) disconnected during association to an IWD Known Network, giving up"); - - return FALSE; - } - - if ( need_new_8021x_secrets (self, &setting_name) - || need_new_wpa_psk (self, &setting_name)) { - nm_act_request_clear_secrets (req); - - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) disconnected during association, asking for new key"); - - cleanup_association_attempt (self, FALSE); - nm_device_state_changed (device, NM_DEVICE_STATE_NEED_AUTH, - NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); - wifi_secrets_get_secrets (self, - setting_name, - NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION - | NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); - handled = TRUE; - } - - return handled; } static void @@ -1235,7 +1156,7 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) error->message); connection = nm_device_get_applied_connection (device); - if (!connection || nm_connection_get_setting_wireless_security (connection)) + if (!connection) goto failed; if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR)) @@ -1243,13 +1164,10 @@ network_connect_cb (GObject *source, GAsyncResult *res, gpointer user_data) /* If secrets were wrong, we'd be getting a net.connman.iwd.Failed */ if (nm_streq0 (dbus_error, "net.connman.iwd.Failed")) { - if (handle_8021x_or_psk_auth_fail (self)) { - _LOGW (LOGD_DEVICE | LOGD_WIFI, "Activation: (wifi) asking for new secrets"); - } else { - cleanup_association_attempt (self, FALSE); - nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_NO_SECRETS); - } + nm_connection_clear_secrets (connection); + + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, + NM_DEVICE_STATE_REASON_NO_SECRETS); } else if ( !nm_utils_error_is_cancelled (error, TRUE) && nm_device_is_activating (device)) goto failed; @@ -1293,36 +1211,6 @@ failed: NM_DEVICE_STATE_REASON_SUPPLICANT_FAILED); } -static gboolean -handle_auth_or_fail (NMDeviceIwd *self, - NMActRequest *req, - gboolean new_secrets) -{ - const char *setting_name; - NMConnection *applied_connection; - NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION; - - g_return_val_if_fail (NM_IS_DEVICE_IWD (self), FALSE); - - if (!nm_device_auth_retries_try_next (NM_DEVICE (self))) - return FALSE; - - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, NM_DEVICE_STATE_REASON_NONE); - - nm_act_request_clear_secrets (req); - applied_connection = nm_act_request_get_applied_connection (req); - setting_name = nm_connection_need_secrets (applied_connection, NULL); - if (!setting_name) { - _LOGW (LOGD_DEVICE, "Cleared secrets, but setting didn't need any secrets."); - return FALSE; - } - - if (new_secrets) - get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW; - wifi_secrets_get_secrets (self, setting_name, get_secret_flags); - return TRUE; -} - /*****************************************************************************/ static NMActStageReturn @@ -1378,8 +1266,6 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) NMActRequest *req; NMWifiAP *ap; NMConnection *connection; - const char *setting_name; - NMSettingWireless *s_wireless; GError *error = NULL; GDBusProxy *network_proxy; @@ -1395,42 +1281,21 @@ act_stage2_config (NMDevice *device, NMDeviceStateReason *out_failure_reason) connection = nm_act_request_get_applied_connection (req); g_assert (connection); - s_wireless = nm_connection_get_setting_wireless (connection); - g_assert (s_wireless); - - /* If we need secrets, get them. If a network is an IWD Known Network the secrets - * will have been stored by IWD and we don't require any secrets here. + /* 802.1x networks that are not IWD Known Networks will definitely + * fail, for other combinations we will let the Connect call fail + * or ask us for any missing secrets through the Agent. */ - if (!is_connection_known_network (connection)) - setting_name = nm_connection_need_secrets (connection, NULL); - else - setting_name = NULL; - - if (setting_name) { + if ( !is_connection_known_network (connection) + && nm_connection_get_setting_802_1x (connection)) { _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) access point '%s' has security, but secrets are required.", + "Activation: (wifi) access point '%s' has 802.1x security, but is not configured.", nm_connection_get_id (connection)); - if (handle_auth_or_fail (self, req, FALSE)) - ret = NM_ACT_STAGE_RETURN_POSTPONE; - else { - NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); - ret = NM_ACT_STAGE_RETURN_FAILURE; - } + NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_NO_SECRETS); + ret = NM_ACT_STAGE_RETURN_FAILURE; goto out; } - /* Have secrets or no secrets required */ - if (nm_connection_get_setting_wireless_security (connection)) { - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) connection '%s' has security, and secrets exist. No new secrets needed.", - nm_connection_get_id (connection)); - } else { - _LOGI (LOGD_DEVICE | LOGD_WIFI, - "Activation: (wifi) connection '%s' requires no security. No secrets needed.", - nm_connection_get_id (connection)); - } - /* Locate the IWD Network object */ network_proxy = g_dbus_proxy_new_for_bus_sync (NM_IWD_BUS_TYPE, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | @@ -1571,7 +1436,6 @@ device_state_changed (NMDevice *device, } break; case NM_DEVICE_STATE_NEED_AUTH: - send_disconnect (self); break; case NM_DEVICE_STATE_IP_CHECK: break; @@ -1731,8 +1595,7 @@ state_changed (NMDeviceIwd *self, const gchar *new_state) _LOGI (LOGD_DEVICE | LOGD_WIFI, "new IWD device state is %s", new_state); if ( dev_state >= NM_DEVICE_STATE_CONFIG - && dev_state <= NM_DEVICE_STATE_ACTIVATED - && dev_state != NM_DEVICE_STATE_NEED_AUTH) + && dev_state <= NM_DEVICE_STATE_ACTIVATED) iwd_connection = TRUE; /* Don't allow scanning while connecting, disconnecting or roaming */ @@ -1776,6 +1639,13 @@ state_changed (NMDeviceIwd *self, const gchar *new_state) */ send_disconnect (self); + /* + * If IWD is still handling the Connect call, let our callback + * for the dbus method handle the failure. + */ + if (dev_state == NM_DEVICE_STATE_CONFIG) + return; + nm_device_state_changed (device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_SUPPLICANT_DISCONNECT); @@ -1881,31 +1751,42 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) send_disconnect (self); } -const gchar * -nm_device_iwd_agent_psk_query (NMDeviceIwd *self) +gboolean +nm_device_iwd_agent_psk_query (NMDeviceIwd *self, + GDBusMethodInvocation *invocation) { + NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self); NMActRequest *req; - NMConnection *connection; - NMSettingWireless *s_wireless; NMSettingWirelessSecurity *s_wireless_sec; + const gchar *psk; req = nm_device_get_act_request (NM_DEVICE (self)); if (!req) - return NULL; + return FALSE; - connection = nm_act_request_get_applied_connection (req); - if (!connection) - return NULL; + s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req)); + if (!s_wireless_sec) + return FALSE; - s_wireless = nm_connection_get_setting_wireless (connection); - if (!s_wireless) - return NULL; + psk = nm_setting_wireless_security_get_psk (s_wireless_sec); + if (psk) { + _LOGD (LOGD_DEVICE | LOGD_WIFI, + "Returning the PSK to the IWD Agent"); - s_wireless_sec = nm_connection_get_setting_wireless_security (connection); - if (!s_wireless_sec) - return NULL; + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)", psk)); + return TRUE; + } - return nm_setting_wireless_security_get_psk (s_wireless_sec); + nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_NEED_AUTH, + NM_DEVICE_STATE_REASON_NO_SECRETS); + wifi_secrets_get_secrets (self, + NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION + | NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW); + + priv->secrets_request = invocation; + return TRUE; } /*****************************************************************************/ @@ -1954,8 +1835,6 @@ dispose (GObject *object) nm_clear_g_source (&priv->periodic_scan_id); - wifi_secrets_cancel (self); - cleanup_association_attempt (self, TRUE); g_clear_object (&priv->dbus_proxy); |