[PATCH 6/6] devices/wifi: Register an IWD PSK agent on dbus



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 1714a4bf2..0d1832787 100644
--- a/src/devices/wifi/nm-device-iwd.c
+++ b/src/devices/wifi/nm-device-iwd.c
@@ -1651,6 +1651,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 15f1767f4..9f83c9fd3 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,
+                                                      NM_IWD_NETWORK_INTERFACE);
+       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,
+                                                     NM_IWD_DEVICE_INTERFACE);
+       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_ERROR_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,
+                                                                            "/",
+                                                                            NM_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);
+       }
+
+       nm_clear_g_free (&priv->agent_path);
 
        nm_clear_g_cancellable (&priv->cancellable);
 
-- 
2.11.0



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]