summary refs log tree commit diff
path: root/src/devices/wifi/nm-device-iwd.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2018-07-01 20:58:23 +0200
committerMichael Biebl <biebl@debian.org>2018-07-01 20:58:23 +0200
commit429393567647935d9123e21fd27a7529d50255eb (patch)
treeb5a99bf0cbbe77fccd7fee81caf71915ccf9eb96 /src/devices/wifi/nm-device-iwd.c
parent069cb5c3a525ebcc19cc2927964258acaca87b13 (diff)
New upstream version 1.12.0 upstream/1.12.0
Diffstat (limited to 'src/devices/wifi/nm-device-iwd.c')
-rw-r--r--src/devices/wifi/nm-device-iwd.c290
1 files changed, 197 insertions, 93 deletions
diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm-device-iwd.c
index d28fcdbd..7667816a 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -73,7 +73,6 @@ typedef struct {
 	GCancellable *  cancellable;
 	NMDeviceWifiCapabilities capabilities;
 	NMActRequestGetSecretsCallId *wifi_secrets_id;
-	GDBusMethodInvocation *secrets_request;
 	guint           periodic_scan_id;
 	bool            enabled:1;
 	bool            can_scan:1;
@@ -379,14 +378,6 @@ wifi_secrets_cancel (NMDeviceIwd *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
@@ -545,7 +536,7 @@ check_connection_compatible (NMDevice *device, NMConnection *connection)
 		return FALSE;
 
 	mode = nm_setting_wireless_get_mode (s_wireless);
-	if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
+	if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
 		return FALSE;
 
 	/* 8021x networks can only be used if they've been provisioned on the IWD side and
@@ -575,7 +566,7 @@ check_connection_available (NMDevice *device,
 
 	/* Only Infrastrusture mode at this time */
 	mode = nm_setting_wireless_get_mode (s_wifi);
-	if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
+	if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
 		return FALSE;
 
 	/* Hidden SSIDs not supported yet */
@@ -630,7 +621,7 @@ complete_connection (NMDevice *device,
 
 	mode = s_wifi ? nm_setting_wireless_get_mode (s_wifi) : NULL;
 
-	if (s_wifi && !nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_INFRA)) {
+	if (mode && !nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_INFRA)) {
 		g_set_error_literal (error,
 		                     NM_DEVICE_ERROR,
 		                     NM_DEVICE_ERROR_INVALID_CONNECTION,
@@ -806,7 +797,7 @@ can_auto_connect (NMDevice *device,
 
 	/* Only Infrastrusture mode */
 	mode = nm_setting_wireless_get_mode (s_wifi);
-	if (g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
+	if (mode && g_strcmp0 (mode, NM_SETTING_WIRELESS_MODE_INFRA) != 0)
 		return FALSE;
 
 	/* Don't autoconnect to networks that have been tried at least once
@@ -1001,6 +992,127 @@ scanning_prohibited (NMDeviceIwd *self, gboolean periodic)
 	return !priv->can_scan;
 }
 
+/*
+ * try_reply_agent_request
+ *
+ * Check if the connection settings already have the secrets corresponding
+ * to the IWD agent method that was invoked.  If they do, send the method reply
+ * with the appropriate secrets.  Otherwise return the missing secret's setting
+ * name and key so the caller can send a NM secrets request with this data.
+ * Return TRUE in either case, return FALSE if an error is detected.
+ */
+static gboolean
+try_reply_agent_request (NMDeviceIwd *self,
+                         NMConnection *connection,
+                         GDBusMethodInvocation *invocation,
+                         const gchar **setting_name,
+                         const gchar **setting_key,
+                         gboolean *replied)
+{
+	const gchar *method_name = g_dbus_method_invocation_get_method_name (invocation);
+	NMSettingWirelessSecurity *s_wireless_sec;
+	NMSetting8021x *s_8021x;
+
+	s_wireless_sec = nm_connection_get_setting_wireless_security (connection);
+	s_8021x = nm_connection_get_setting_802_1x (connection);
+
+	*replied = FALSE;
+
+	if (!strcmp (method_name, "RequestPassphrase")) {
+		const gchar *psk;
+
+		if (!s_wireless_sec)
+			return FALSE;
+
+		psk = nm_setting_wireless_security_get_psk (s_wireless_sec);
+		if (psk) {
+			_LOGD (LOGD_DEVICE | LOGD_WIFI,
+			       "Returning the PSK to the IWD Agent");
+
+			g_dbus_method_invocation_return_value (invocation,
+			                                       g_variant_new ("(s)", psk));
+			*replied = TRUE;
+			return TRUE;
+		}
+
+		*setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME;
+		*setting_key = NM_SETTING_WIRELESS_SECURITY_PSK;
+		return TRUE;
+	} else if (!strcmp (method_name, "RequestPrivateKeyPassphrase")) {
+		const gchar *password;
+
+		if (!s_8021x)
+			return FALSE;
+
+		password = nm_setting_802_1x_get_private_key_password (s_8021x);
+		if (password) {
+			_LOGD (LOGD_DEVICE | LOGD_WIFI,
+			       "Returning the private key password to the IWD Agent");
+
+			g_dbus_method_invocation_return_value (invocation,
+			                                       g_variant_new ("(s)", password));
+			*replied = TRUE;
+			return TRUE;
+		}
+
+		*setting_name = NM_SETTING_802_1X_SETTING_NAME;
+		*setting_key = NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD;
+		return TRUE;
+	} else if (!strcmp (method_name, "RequestUserNameAndPassword")) {
+		const gchar *identity, *password;
+
+		if (!s_8021x)
+			return FALSE;
+
+		identity = nm_setting_802_1x_get_identity (s_8021x);
+		password = nm_setting_802_1x_get_password (s_8021x);
+		if (identity && password) {
+			_LOGD (LOGD_DEVICE | LOGD_WIFI,
+			       "Returning the username and password to the IWD Agent");
+
+			g_dbus_method_invocation_return_value (invocation,
+			                                       g_variant_new ("(ss)", identity, password));
+			*replied = TRUE;
+			return TRUE;
+		}
+
+		*setting_name = NM_SETTING_802_1X_SETTING_NAME;
+		if (!identity)
+			*setting_key = NM_SETTING_802_1X_IDENTITY;
+		else
+			*setting_key = NM_SETTING_802_1X_PASSWORD;
+		return TRUE;
+	} else if (!strcmp (method_name, "RequestUserPassword")) {
+		const gchar *password;
+
+		if (!s_8021x)
+			return FALSE;
+
+		password = nm_setting_802_1x_get_password (s_8021x);
+		if (password) {
+			_LOGD (LOGD_DEVICE | LOGD_WIFI,
+			       "Returning the user password to the IWD Agent");
+
+			g_dbus_method_invocation_return_value (invocation,
+			                                       g_variant_new ("(s)", password));
+			*replied = TRUE;
+			return TRUE;
+		}
+
+		*setting_name = NM_SETTING_802_1X_SETTING_NAME;
+		*setting_key = NM_SETTING_802_1X_PASSWORD;
+		return TRUE;
+	} else
+		return FALSE;
+}
+
+static void
+wifi_secrets_get_one (NMDeviceIwd *self,
+                      const char *setting_name,
+                      NMSecretAgentGetSecretsFlags flags,
+                      const char *setting_key,
+                      GDBusMethodInvocation *invocation);
+
 static void
 wifi_secrets_cb (NMActRequest *req,
                  NMActRequestGetSecretsCallId *call_id,
@@ -1008,25 +1120,33 @@ wifi_secrets_cb (NMActRequest *req,
                  GError *error,
                  gpointer user_data)
 {
-	NMDevice *device = user_data;
-	NMDeviceIwd *self = user_data;
+	NMDeviceIwd *self;
 	NMDeviceIwdPrivate *priv;
-	NMSettingWirelessSecurity *s_wireless_sec;
-	const gchar *psk;
+	NMDevice *device;
+	GDBusMethodInvocation *invocation;
+	const gchar *setting_name;
+	const gchar *setting_key;
+	gboolean replied;
+	NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION;
+
+	nm_utils_user_data_unpack (user_data, &self, &invocation);
 
 	g_return_if_fail (NM_IS_DEVICE_IWD (self));
-	g_return_if_fail (NM_IS_ACT_REQUEST (req));
 
 	priv = NM_DEVICE_IWD_GET_PRIVATE (self);
+	device = NM_DEVICE (self);
 
 	g_return_if_fail (priv->wifi_secrets_id == call_id);
 
 	priv->wifi_secrets_id = NULL;
 
-	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+	if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
+		g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR,
+		                                               NM_DEVICE_ERROR_INVALID_CONNECTION,
+		                                               "NM secrets request 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_act_request_get_settings_connection (req) == s_connection);
 
@@ -1038,32 +1158,30 @@ wifi_secrets_cb (NMActRequest *req,
 		goto secrets_error;
 	}
 
-	s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req));
-	if (!s_wireless_sec)
-		goto secrets_error;
-
-	psk = nm_setting_wireless_security_get_psk (s_wireless_sec);
-	if (!psk)
+	if (!try_reply_agent_request (self, nm_act_request_get_applied_connection (req),
+	                              invocation, &setting_name, &setting_key,
+	                              &replied))
 		goto secrets_error;
 
-	_LOGD (LOGD_DEVICE | LOGD_WIFI,
-	       "Returning a new PSK to the IWD Agent");
+	if (replied) {
+		/* 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;
+	}
 
-	g_dbus_method_invocation_return_value (priv->secrets_request,
-	                                       g_variant_new ("(s)", psk));
-	priv->secrets_request = NULL;
+	if (nm_settings_connection_get_timestamp (nm_act_request_get_settings_connection (req),
+	                                          NULL))
+		get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW;
 
-	/* Change state back to what it was before NEED_AUTH */
-	nm_device_state_changed (device, NM_DEVICE_STATE_CONFIG, NM_DEVICE_STATE_REASON_NONE);
+	/* Request further secrets if we still need something */
+	wifi_secrets_get_one (self, setting_name, get_secret_flags,
+	                      setting_key, invocation);
 	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;
-	}
+	g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR,
+	                                               NM_DEVICE_ERROR_INVALID_CONNECTION,
+	                                               "NM secrets request failed");
 
 	nm_device_state_changed (device,
 	                         NM_DEVICE_STATE_FAILED,
@@ -1073,9 +1191,11 @@ secrets_error:
 }
 
 static void
-wifi_secrets_get_secrets (NMDeviceIwd *self,
-                          const char *setting_name,
-                          NMSecretAgentGetSecretsFlags flags)
+wifi_secrets_get_one (NMDeviceIwd *self,
+                      const char *setting_name,
+                      NMSecretAgentGetSecretsFlags flags,
+                      const char *setting_key,
+                      GDBusMethodInvocation *invocation)
 {
 	NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self);
 	NMActRequest *req;
@@ -1089,9 +1209,9 @@ wifi_secrets_get_secrets (NMDeviceIwd *self,
 	                                                    TRUE,
 	                                                    setting_name,
 	                                                    flags,
-	                                                    NULL,
+	                                                    setting_key,
 	                                                    wifi_secrets_cb,
-	                                                    self);
+	                                                    nm_utils_user_data_pack (self, invocation));
 }
 
 static void
@@ -1219,15 +1339,13 @@ act_stage1_prepare (NMDevice *device, NMDeviceStateReason *out_failure_reason)
 	ap = ap_path ? nm_wifi_ap_lookup_for_device (NM_DEVICE (self), ap_path) : NULL;
 	if (!ap) {
 		ap = nm_wifi_aps_find_first_compatible (&priv->aps_lst_head, connection);
-
-		/* TODO: assuming hidden networks aren't supported do we need
-		 * to consider the case of APs that are not in the scan list
-		 * yet, for which nm-device-wifi.c creates the temporary fake
-		 * AP object?
-		 */
+		if (!ap) {
+			NM_SET_OUT (out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED);
+			return NM_ACT_STAGE_RETURN_FAILURE;
+		}
 
 		nm_active_connection_set_specific_object (NM_ACTIVE_CONNECTION (req),
-	                                              nm_dbus_object_get_path (NM_DBUS_OBJECT (ap)));
+		                                          nm_dbus_object_get_path (NM_DBUS_OBJECT (ap)));
 	}
 
 	set_current_ap (self, ap, FALSE);
@@ -1316,29 +1434,11 @@ out:
 }
 
 static guint32
-get_configured_mtu (NMDevice *device, gboolean *out_is_user_config)
+get_configured_mtu (NMDevice *device, NMDeviceMtuSource *out_source)
 {
-	NMSettingWireless *setting;
-	gint64 mtu_default;
-	guint32 mtu;
-
-	nm_assert (NM_IS_DEVICE (device));
-	nm_assert (out_is_user_config);
-
-	setting = NM_SETTING_WIRELESS (nm_device_get_applied_setting (device, NM_TYPE_SETTING_WIRELESS));
-	if (!setting)
-		g_return_val_if_reached (0);
-
-	mtu = nm_setting_wireless_get_mtu (setting);
-	if (mtu == 0) {
-		mtu_default = nm_device_get_configured_mtu_from_connection_default (device, "wifi.mtu");
-		if (mtu_default >= 0) {
-			*out_is_user_config = TRUE;
-			return (guint32) mtu_default;
-		}
-	}
-	*out_is_user_config = (mtu != 0);
-	return mtu;
+	return nm_device_get_configured_mtu_from_connection (device,
+	                                                     NM_TYPE_SETTING_WIRELESS,
+	                                                     out_source);
 }
 
 static gboolean
@@ -1748,40 +1848,44 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object)
 }
 
 gboolean
-nm_device_iwd_agent_psk_query (NMDeviceIwd *self,
-                               GDBusMethodInvocation *invocation)
+nm_device_iwd_agent_query (NMDeviceIwd *self,
+                           GDBusMethodInvocation *invocation)
 {
-	NMDeviceIwdPrivate *priv = NM_DEVICE_IWD_GET_PRIVATE (self);
 	NMActRequest *req;
-	NMSettingWirelessSecurity *s_wireless_sec;
-	const gchar *psk;
+	const gchar *setting_name;
+	const gchar *setting_key;
+	gboolean replied;
+	NMSecretAgentGetSecretsFlags get_secret_flags = NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION;
 
 	req = nm_device_get_act_request (NM_DEVICE (self));
 	if (!req)
 		return FALSE;
 
-	s_wireless_sec = nm_connection_get_setting_wireless_security (nm_act_request_get_applied_connection (req));
-	if (!s_wireless_sec)
+	if (!try_reply_agent_request (self, nm_act_request_get_applied_connection (req),
+	                              invocation, &setting_name, &setting_key,
+	                              &replied))
 		return FALSE;
 
-	psk = nm_setting_wireless_security_get_psk (s_wireless_sec);
-	if (psk) {
-		_LOGD (LOGD_DEVICE | LOGD_WIFI,
-		       "Returning the PSK to the IWD Agent");
-
-		g_dbus_method_invocation_return_value (invocation,
-		                                       g_variant_new ("(s)", psk));
+	if (replied)
 		return TRUE;
-	}
+
+	/* Normally require new secrets every time IWD asks for them.
+	 * IWD only queries us if it has not saved the secrets (e.g. by policy)
+	 * or a previous attempt has failed with current secrets so it wants
+	 * a fresh set.  However if this is a new connection it may include
+	 * all of the needed settings already so allow using these, too.
+	 * Connection timestamp is set after activation or after first
+	 * activation failure (to 0).
+	 */
+	if (nm_settings_connection_get_timestamp (nm_act_request_get_settings_connection (req),
+	                                          NULL))
+		get_secret_flags |= NM_SECRET_AGENT_GET_SECRETS_FLAG_REQUEST_NEW;
 
 	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);
+	wifi_secrets_get_one (self, setting_name, get_secret_flags,
+	                      setting_key, invocation);
 
-	priv->secrets_request = invocation;
 	return TRUE;
 }