On Tue, 2017-12-05 at 16:26 +0100, Andrew Zaborowski wrote:
Add the PSK agent support to support PSK networks. Note that the PSK itself will be saved by IWD on the first successful connection to the network and will not be updated when it is changed by the user on the NM side, this still needs fixing like a bunch of other problems. --- src/devices/wifi/nm-device-iwd.c | 27 +++++ src/devices/wifi/nm-device-iwd.h | 2 + src/devices/wifi/nm-iwd-manager.c | 205 +++++++++++++++++++++++++++++++++++++- 3 files changed, 233 insertions(+), 1 deletion(-) diff --git a/src/devices/wifi/nm-device-iwd.c b/src/devices/wifi/nm- device-iwd.c index e2be47bcb..b4cb87d14 100644 --- a/src/devices/wifi/nm-device-iwd.c +++ b/src/devices/wifi/nm-device-iwd.c @@ -1766,6 +1766,33 @@ nm_device_iwd_set_dbus_object (NMDeviceIwd *self, GDBusObject *object) send_disconnect (self); } +const gchar * +nm_device_iwd_agent_psk_query (NMDeviceIwd *self) +{ + NMActRequest *req; + NMConnection *connection; + NMSettingWireless *s_wireless; + NMSettingWirelessSecurity *s_wireless_sec; + + req = nm_device_get_act_request (NM_DEVICE (self)); + if (!req) + return NULL; + + connection = nm_act_request_get_applied_connection (req); + if (!connection) + return NULL; + + s_wireless = nm_connection_get_setting_wireless (connection); + if (!s_wireless) + return NULL; + + s_wireless_sec = nm_connection_get_setting_wireless_security (connection); + if (!s_wireless_sec) + return NULL; + + return nm_setting_wireless_security_get_psk (s_wireless_sec); +} + /******************************************************************* **********/ static void diff --git a/src/devices/wifi/nm-device-iwd.h b/src/devices/wifi/nm- device-iwd.h index 34cdad0d0..332f4282c 100644 --- a/src/devices/wifi/nm-device-iwd.h +++ b/src/devices/wifi/nm-device-iwd.h @@ -55,4 +55,6 @@ NMDevice *nm_device_iwd_new (const char *iface, NMDeviceWifiCapabilities capabil void nm_device_iwd_set_dbus_object (NMDeviceIwd *device, GDBusObject *object); +const gchar *nm_device_iwd_agent_psk_query (NMDeviceIwd *device); + #endif /* __NETWORKMANAGER_DEVICE_IWD_H__ */ diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm- iwd-manager.c index 7561b17b3..a27ecd388 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -35,6 +35,8 @@ typedef struct { GCancellable *cancellable; gboolean running; GDBusObjectManager *object_manager; + guint agent_id; + gchar *agent_path; } NMIwdManagerPrivate; struct _NMIWDManager { @@ -73,6 +75,165 @@ G_DEFINE_TYPE (NMIwdManager, nm_iwd_manager, G_TYPE_OBJECT) /******************************************************************* **********/ static void +psk_agent_dbus_method_cb (GDBusConnection *connection, + const gchar *sender, const gchar *object_path, + const gchar *interface_name, const gchar *method_name, + GVariant *parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) +{ + NMIwdManager *self = user_data; + NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); + GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager); + const gchar *network_path, *device_path, *ifname; + gs_unref_object GDBusInterface *network = NULL, *device_obj = NULL; + gs_unref_variant GVariant *value = NULL; + gint ifindex; + NMManager *manager; + NMDevice *device; + const gchar *psk; + + /* Be paranoid and check the sender address */ + if (!nm_streq0 (g_dbus_object_manager_client_get_name_owner (omc), sender)) + goto return_error; + + g_variant_get (parameters, "(&o)", &network_path); + + network = g_dbus_object_manager_get_interface (priv-object_manager,+ network_path, + IWD_NETWORK_I NTERFACE); + value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (network), "Device"); + device_path = g_variant_get_string (value, NULL); + + if (!device_path) { + _LOGE ("Device not cached for network %s in IWD Agent request", + network_path); + goto return_error; + } + + device_obj = g_dbus_object_manager_get_interface (priv-object_manager,+ device_path, + IWD_DEVICE_INT ERFACE); + g_variant_unref (value); + value = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (device_obj), "Name"); + ifname = g_variant_get_string (value, NULL); + + if (!ifname) { + _LOGE ("Name not cached for device %s in IWD Agent request", + device_path); + goto return_error; + } + + ifindex = if_nametoindex (ifname); + if (!ifindex) { + _LOGE ("if_nametoindex failed for Name %s for Device at %s: %i", + ifname, device_path, errno); + goto return_error; + } + + manager = nm_manager_get (); + + device = nm_manager_get_device_by_ifindex (manager, ifindex); + if (!NM_IS_DEVICE_IWD (device)) { + _LOGE ("IWD device named %s is not a Wifi device in IWD Agent request", + ifname); + goto return_error; + } + + psk = nm_device_iwd_agent_psk_query (NM_DEVICE_IWD (device)); + if (!psk) { + _LOGW ("Device %s had no PSK for the IWD Agent", ifname); + goto return_error; + } + + _LOGI ("Sending the PSK to the IWD Agent for device %s", ifname); + g_dbus_method_invocation_return_value (invocation, + g_variant_new ("(s)", psk)); + return; + +return_error: + /* IWD doesn't look at the specific error */ + g_dbus_method_invocation_return_error_literal (invocation, NM_DEVICE_ERROR, + NM_DEVICE_ERR OR_INVALID_CONNECTION, + "No PSK available for this connection"); +} + + +static guint +psk_agent_export (GDBusConnection *connection, gpointer user_data, + gchar **agent_path, GError **error) +{ + static const GDBusArgInfo request_passphrase_arg_network = { + -1, + (gchar *) "network", + (gchar *) "o", + NULL, + }; + static const GDBusArgInfo *const request_passphrase_in_args[] = { + &request_passphrase_arg_network, + NULL, + }; + static const GDBusArgInfo request_passphrase_arg_passphrase = { + -1, + (gchar *) "passphrase", + (gchar *) "s", + NULL, + }; + static const GDBusArgInfo *const request_passphrase_out_args[] = { + &request_passphrase_arg_passphrase, + NULL, + }; + static const GDBusMethodInfo request_passphrase_info = { + -1, + (gchar *) "RequestPassphrase", + (GDBusArgInfo **) &request_passphrase_in_args, + (GDBusArgInfo **) &request_passphrase_out_args, + NULL, + }; + static const GDBusMethodInfo *const method_info[] = { + &request_passphrase_info, + NULL, + }; + static GDBusInterfaceInfo interface_info = { + -1, + (gchar *) "net.connman.iwd.Agent", + (GDBusMethodInfo **) &method_info, + NULL, + NULL, + NULL, + }; + static GDBusInterfaceVTable vtable = { + psk_agent_dbus_method_cb, + NULL, + NULL, + }; + + gchar path[50]; + unsigned int rnd; + guint id; + + if (nm_utils_read_urandom (&rnd, sizeof (rnd)) < 0) { + g_set_error_literal (error, + NM_DEVICE_ERROR, + NM_DEVICE_ERROR_FAILED, + "Can't read urandom."); + return 0; + } + + nm_sprintf_buf (path, "/agent/%u", rnd); + + id = g_dbus_connection_register_object (connection, path, + &interface_info, &vtable, + user_data, NULL, error); + + if (id) + *agent_path = g_strdup (path); + return id; +} + +/******************************************************************* **********/ + +static void set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface, GDBusObject *object) { @@ -193,6 +354,23 @@ name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data) object_added (self, G_DBUS_OBJECT (iter-data));g_list_free_full (objects, g_object_unref); + + if (priv->agent_id) { + GDBusInterface *agent_manager; + + agent_manager = g_dbus_object_manager_get_interface (object_manager, + "/", + IWD_AGENT_MANAGER_INTERFACE); + + /* Register our agent */ + g_dbus_proxy_call (G_DBUS_PROXY (agent_manager), + "RegisterAgent", + g_variant_new ("(o)", priv->agent_path), + G_DBUS_CALL_FLAGS_NONE, -1, + NULL, NULL, NULL); + + g_object_unref (agent_manager); + } } else { NMManager *manager = nm_manager_get (); const GSList *devices, *iter; @@ -292,6 +470,14 @@ got_object_manager (GObject *object, GAsyncResult *result, gpointer user_data) connection = g_dbus_object_manager_client_get_connection (G_DBUS_OBJECT_MANAGER_CLIENT (object_manager)); + priv->agent_id = psk_agent_export (connection, self, + &priv->agent_path, &error); + if (!priv->agent_id) { + _LOGE ("failed to export the IWD Agent: PSK/8021x WiFi networks will not work: %s", + NM_G_ERROR_MSG (error)); + g_clear_error (&error); + } + name_owner_changed (G_OBJECT (object_manager), NULL, self); g_signal_connect (manager, "device-added", @@ -331,8 +517,25 @@ dispose (GObject *object) NMIwdManager *self = (NMIwdManager *) object; NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self); - if (priv->object_manager) + if (priv->object_manager) { + if (priv->agent_id) { + GDBusConnection *connection; + GDBusObjectManagerClient *omc = G_DBUS_OBJECT_MANAGER_CLIENT (priv->object_manager); + + /* No need to unregister the agent as IWD will detect + * our DBus connection being closed. + */ + + connection = g_dbus_object_manager_client_get_connection (omc); + + g_dbus_connection_unregister_object (connection, priv->agent_id); + priv->agent_id = 0; + } + g_clear_object (&priv->object_manager); + } + + g_free (priv->agent_path);
dispose() must be re-entrant. Meaning, you should not leave dangling pointers. For example, use nm_clear_g_free (&priv->agent_path).
nm_clear_g_cancellable (&priv->cancellable);
Attachment:
signature.asc
Description: This is a digitally signed message part