]> git.ipfire.org Git - thirdparty/hostap.git/commitdiff
D-Bus: Interworking/Hotspot 2.0 credential operations
authorDamien Dejean <damiendejean@chromium.org>
Wed, 8 Dec 2021 07:45:31 +0000 (07:45 +0000)
committerJouni Malinen <j@w1.fi>
Sun, 12 Dec 2021 15:32:51 +0000 (17:32 +0200)
Add "AddCred", "RemoveCred", and "RemoveAllCreds" methods to the D-Bus
API of the network interface to allow the caller to manipulate a set of
Interworking credentials similarly to the way this was enabled through
the control interface.

Signed-off-by: Damien Dejean <damiendejean@chromium.org>
doc/dbus.doxygen
tests/hwsim/test_dbus.py
wpa_supplicant/dbus/dbus_new.c
wpa_supplicant/dbus/dbus_new.h
wpa_supplicant/dbus/dbus_new_handlers.c
wpa_supplicant/dbus/dbus_new_handlers.h

index 8231aac418055ff5c0f1bf8ea698dcea0d55d0cf..68fc84572ee4ef43b2723c354d91ea3200543b2f 100644 (file)
@@ -552,6 +552,28 @@ fi.w1.wpa_supplicant1.CreateInterface.
        <h3>AbortScan ( ) --> nothing</h3>
        <p>Abort ongoing scan operation.</p>
       </li>
+      <li>
+       <h3>AddCred ( a{sv} : args ) -->  o : path</h3>
+       <p>Add an Interworking/Hotspot 2.0 credential.</p>
+       <h4>Arguments</h4>
+       <dl>
+         <dt>a{sv} : args</dt>
+         <dd>A dictionary with credential configuration. Dictionary entries are equivalent to entries in the "cred" block in wpa_supplicant configuration file.</dd>
+       </dl>
+       <h4>Returns</h4>
+       <dl>
+         <dt>o : path</dt>
+         <dd>A D-Bus path to an object representing the added credential</dd>
+       </dl>
+      </li>
+      <li>
+       <h3>RemoveCred ( o : path ) --> nothing</h3>
+       <p>Remove the specified Interworking/Hotspot 2.0 credential.</p>
+      </li>
+      <li>
+       <h3>RemoveAllCreds ( ) --> nothing</h3>
+       <p>Remove all configured Interworking/Hotspot 2.0 credentials.</p>
+      </li>
       <li>
        <h3>EAPLogoff ( ) --> nothing</h3>
        <p>IEEE 802.1X EAPOL state machine logoff.</p>
index 1143802c613171a5bcdbeb7faba7b96e73b1b1e7..4edd0fd7359c73ee54ddccf787df3892c50ad1ea 100644 (file)
@@ -6091,3 +6091,48 @@ def test_dbus_roam(dev, apdev):
     with TestDbusConnect(bus) as t:
         if not t.success():
             raise Exception("Expected signals not seen")
+
+def test_dbus_creds(dev, apdev):
+    "D-Bus interworking credentials"
+    (bus, wpas_obj, path, if_obj) = prepare_dbus(dev[0])
+    iface = dbus.Interface(if_obj, WPAS_DBUS_IFACE)
+
+    args = {'domain': 'server.w1.fi',
+            'realm': 'server.w1.fi',
+            'roaming_consortium': '50a9bf',
+            'required_roaming_consortium': '23bf50',
+            'eap': 'TTLS',
+            'phase2': 'auth=MSCHAPV2',
+            'username': 'user',
+            'password': 'password',
+            'domain_suffix_match': 'server.w1.fi',
+            'ca_cert': 'auth_serv/ca.pem'}
+
+    path = iface.AddCred(dbus.Dictionary(args, signature='sv'))
+    for k, v in args.items():
+        if k == 'password':
+            continue
+        prop = dev[0].get_cred(0, k)
+        if prop != v:
+            raise Exception('Credential add failed: %s does not match %s' % (prop, v))
+
+    iface.RemoveCred(path)
+    if not "FAIL" in dev[0].get_cred(0, 'domain'):
+        raise Exception("Credential remove failed")
+
+    # Removal of multiple credentials
+    cred1 = {'domain': 'server1.w1.fi','realm': 'server1.w1.fi','eap': 'TTLS'}
+    iface.AddCred(dbus.Dictionary(cred1, signature='sv'))
+    if "FAIL" in dev[0].get_cred(0, 'domain'):
+        raise Exception("Failed to add credential")
+
+    cred2 = {'domain': 'server2.w1.fi','realm': 'server2.w1.fi','eap': 'TTLS'}
+    iface.AddCred(dbus.Dictionary(cred2, signature='sv'))
+    if "FAIL" in dev[0].get_cred(1, 'domain'):
+        raise Exception("Failed to add credential")
+
+    iface.RemoveAllCreds()
+    if not "FAIL" in dev[0].get_cred(0, 'domain'):
+        raise Exception("Credential remove failed")
+    if not "FAIL" in dev[0].get_cred(1, 'domain'):
+        raise Exception("Credential remove failed")
index 2c01943f754e9d4e4b5d16dc5d29c756754c0f69..bfa49d65465943c4856f07db0548823b7dc5b2e7 100644 (file)
@@ -3570,6 +3570,29 @@ static const struct wpa_dbus_method_desc wpas_dbus_interface_methods[] = {
                  END_ARGS
          }
        },
+#ifdef CONFIG_INTERWORKING
+       { "AddCred", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_add_cred,
+         {
+                 { "args", "a{sv}", ARG_IN },
+                 { "path", "o", ARG_OUT },
+                 END_ARGS
+         }
+       },
+       { "RemoveCred", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_remove_cred,
+         {
+                 { "path", "o", ARG_IN },
+                 END_ARGS
+         }
+       },
+       { "RemoveAllCreds", WPAS_DBUS_NEW_IFACE_INTERFACE,
+         (WPADBusMethodHandler) wpas_dbus_handler_remove_all_creds,
+         {
+                 END_ARGS
+         }
+       },
+#endif /* CONFIG_INTERWORKING */
        { NULL, NULL, NULL, { END_ARGS } }
 };
 
index 42db3892ed77e639d8d3097e93dff3c4646c2f74..6cdd9dc166f0a23b84d7ed0b4f7ff2d31106879d 100644 (file)
@@ -96,6 +96,9 @@ enum wpas_dbus_sta_prop {
 #define WPAS_DBUS_NEW_P2P_PEERS_PART   "Peers"
 #define        WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
 
+#define WPAS_DBUS_NEW_CREDENTIALS_PART "Credentials"
+#define WPAS_DBUS_NEW_IFACE_CREDENTIAL WPAS_DBUS_NEW_INTERFACE ".Credential"
+
 /* Top-level Errors */
 #define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
        WPAS_DBUS_NEW_INTERFACE ".UnknownError"
index db9f30c9aabf3a2d82dbe7581b46cbbd8feecc22..ce6923e9527fe11ad47bbc8405de77d883e98bb5 100644 (file)
@@ -148,6 +148,9 @@ static const char * const dont_quote[] = {
 #ifdef CONFIG_P2P
        "go_p2p_dev_addr", "p2p_client_list", "psk_list",
 #endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+       "roaming_consortium", "required_roaming_consortium",
+#endif /* CONFIG_INTERWORKING */
        NULL
 };
 
@@ -328,6 +331,110 @@ error:
 }
 
 
+/**
+ * set_cred_properties - Set the properties of a configured credential
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @cred: wpa_cred structure for a configured credential
+ * @iter: DBus message iterator containing dictionary of network
+ * properties to set.
+ * @error: On failure, an error describing the failure
+ * Returns: TRUE if the request succeeds, FALSE if it failed
+ */
+static dbus_bool_t set_cred_properties(struct wpa_supplicant *wpa_s,
+                                      struct wpa_cred *cred,
+                                      DBusMessageIter *iter,
+                                      DBusError *error)
+{
+       struct wpa_dbus_dict_entry entry = { .type = DBUS_TYPE_STRING };
+       DBusMessageIter iter_dict;
+       char *value = NULL;
+
+       if (!wpa_dbus_dict_open_read(iter, &iter_dict, error))
+               return FALSE;
+
+       while (wpa_dbus_dict_has_dict_entry(&iter_dict)) {
+               size_t size = 50;
+               int ret;
+
+               if (!wpa_dbus_dict_get_entry(&iter_dict, &entry))
+                       goto error;
+
+               value = NULL;
+               if (entry.type == DBUS_TYPE_ARRAY &&
+                   entry.array_type == DBUS_TYPE_BYTE) {
+                       if (entry.array_len <= 0)
+                               goto error;
+
+                       size = entry.array_len * 2 + 1;
+                       value = os_zalloc(size);
+                       if (!value)
+                               goto error;
+
+                       ret = wpa_snprintf_hex(value, size,
+                                              (u8 *) entry.bytearray_value,
+                                              entry.array_len);
+                       if (ret <= 0)
+                               goto error;
+               } else if (entry.type == DBUS_TYPE_STRING) {
+                       if (should_quote_opt(entry.key)) {
+                               size = os_strlen(entry.str_value);
+
+                               size += 3;
+                               value = os_zalloc(size);
+                               if (!value)
+                                       goto error;
+
+                               ret = os_snprintf(value, size, "\"%s\"",
+                                                 entry.str_value);
+                               if (os_snprintf_error(size, ret))
+                                       goto error;
+                       } else {
+                               value = os_strdup(entry.str_value);
+                               if (!value)
+                                       goto error;
+                       }
+               } else if (entry.type == DBUS_TYPE_UINT32) {
+                       value = os_zalloc(size);
+                       if (!value)
+                               goto error;
+
+                       ret = os_snprintf(value, size, "%u",
+                                         entry.uint32_value);
+                       if (os_snprintf_error(size, ret))
+                               goto error;
+               } else if (entry.type == DBUS_TYPE_INT32) {
+                       value = os_zalloc(size);
+                       if (!value)
+                               goto error;
+
+                       ret = os_snprintf(value, size, "%d",
+                                         entry.int32_value);
+                       if (os_snprintf_error(size, ret))
+                               goto error;
+               } else {
+                       goto error;
+               }
+
+               ret = wpa_config_set_cred(cred, entry.key, value, 0);
+               if (ret < 0)
+                       goto error;
+
+               os_free(value);
+               value = NULL;
+               wpa_dbus_dict_entry_clear(&entry);
+       }
+
+       return TRUE;
+
+error:
+       os_free(value);
+       wpa_dbus_dict_entry_clear(&entry);
+       dbus_set_error_const(error, DBUS_ERROR_INVALID_ARGS,
+                            "invalid message format");
+       return FALSE;
+}
+
+
 /**
  * wpas_dbus_simple_property_getter - Get basic type property
  * @iter: Message iter to use when appending arguments
@@ -1515,6 +1622,163 @@ DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message,
 }
 
 
+/**
+ * wpas_dbus_new_iface_add_cred - Add a new credential
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing the object path of the new credential
+ *
+ * Handler function for "AddCred" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message,
+                                        struct wpa_supplicant *wpa_s)
+{
+       DBusMessage *reply = NULL;
+       DBusMessageIter iter;
+       struct wpa_cred *cred = NULL;
+       char path_buf[WPAS_DBUS_OBJECT_PATH_MAX], *path = path_buf;
+       DBusError error;
+
+       dbus_message_iter_init(message, &iter);
+
+       if (wpa_s->dbus_new_path)
+               cred = wpa_config_add_cred(wpa_s->conf);
+       if (!cred) {
+               wpa_printf(MSG_ERROR, "%s[dbus]: can't add new credential.",
+                          __func__);
+               reply = wpas_dbus_error_unknown_error(
+                       message,
+                       "wpa_supplicant could not add a credential on this interface.");
+               goto err;
+       }
+
+       dbus_error_init(&error);
+       if (!set_cred_properties(wpa_s, cred, &iter, &error)) {
+               wpa_printf(MSG_DEBUG,
+                          "%s[dbus]: control interface couldn't set credential properties",
+                          __func__);
+               reply = wpas_dbus_reply_new_from_error(message, &error,
+                                                      DBUS_ERROR_INVALID_ARGS,
+                                                      "Failed to add credential");
+               dbus_error_free(&error);
+               goto err;
+       }
+
+       /* Construct the object path for this network. */
+       os_snprintf(path, WPAS_DBUS_OBJECT_PATH_MAX,
+                   "%s/" WPAS_DBUS_NEW_CREDENTIALS_PART "/%d",
+                   wpa_s->dbus_new_path, cred->id);
+
+       reply = dbus_message_new_method_return(message);
+       if (!reply) {
+               reply = wpas_dbus_error_no_memory(message);
+               goto err;
+       }
+       if (!dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
+                                     DBUS_TYPE_INVALID)) {
+               dbus_message_unref(reply);
+               reply = wpas_dbus_error_no_memory(message);
+               goto err;
+       }
+
+       return reply;
+
+err:
+       if (cred)
+               wpa_config_remove_cred(wpa_s->conf, cred->id);
+       return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_remove_cred - Remove a configured credential
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL on success or dbus error on failure
+ *
+ * Handler function for "RemoveCred" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message,
+                                           struct wpa_supplicant *wpa_s)
+{
+       DBusMessage *reply = NULL;
+       const char *op;
+       char *iface, *cred_id;
+       int id;
+       struct wpa_cred *cred;
+
+       dbus_message_get_args(message, NULL, DBUS_TYPE_OBJECT_PATH, &op,
+                             DBUS_TYPE_INVALID);
+
+       /* Extract the network ID and ensure the network is actually a child of
+        * this interface */
+       iface = wpas_dbus_new_decompose_object_path(
+               op, WPAS_DBUS_NEW_CREDENTIALS_PART, &cred_id);
+       if (!iface || !cred_id || !wpa_s->dbus_new_path ||
+           os_strcmp(iface, wpa_s->dbus_new_path) != 0) {
+               reply = wpas_dbus_error_invalid_args(message, op);
+               goto out;
+       }
+
+       errno = 0;
+       id = strtoul(cred_id, NULL, 10);
+       if (errno != 0) {
+               reply = wpas_dbus_error_invalid_args(message, op);
+               goto out;
+       }
+
+       cred = wpa_config_get_cred(wpa_s->conf, id);
+       if (!cred) {
+               wpa_printf(MSG_ERROR, "%s[dbus]: could not find credential %s",
+                          __func__, op);
+               reply = wpas_dbus_error_invalid_args(
+                       message, "could not find credential");
+               goto out;
+       }
+
+       if (wpas_remove_cred(wpa_s, cred) < 0) {
+               wpa_printf(MSG_ERROR,
+                          "%s[dbus]: error occurred when removing cred %d",
+                          __func__, id);
+               reply = wpas_dbus_error_unknown_error(
+                       message,
+                       "error removing the specified credential on its interface.");
+               goto out;
+       }
+
+out:
+       os_free(iface);
+       return reply;
+}
+
+
+/**
+ * wpas_dbus_handler_remove_all_creds - Remove all the configured credentials
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: NULL indicating success or DBus error message on failure
+ *
+ * Handler function for "RemoveAllCreds" method call of a network interface.
+ */
+DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message,
+                                                struct wpa_supplicant *wpa_s)
+{
+       int res;
+       DBusMessage *reply = NULL;
+
+       res = wpas_remove_all_creds(wpa_s);
+       if (res < 0) {
+               wpa_printf(MSG_ERROR,
+                          "%s[dbus]: failed to remove all credentials",
+                          __func__);
+               reply = wpas_dbus_error_unknown_error(
+                       message, "failed to remove all credentials");
+       }
+
+       return reply;
+}
+
+
 /**
  * wpas_dbus_handler_signal_poll - Request immediate signal properties
  * @message: Pointer to incoming dbus message
index c36383f05668857596bb32c924c16a85b9d8ebb0..1496f5535a862d434c2561f8aa048d89389d1c3e 100644 (file)
@@ -144,6 +144,15 @@ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message,
 DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message,
                                          struct wpa_supplicant *wpa_s);
 
+DBusMessage * wpas_dbus_handler_add_cred(DBusMessage *message,
+                                        struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_cred(DBusMessage *message,
+                                           struct wpa_supplicant *wpa_s);
+
+DBusMessage * wpas_dbus_handler_remove_all_creds(DBusMessage *message,
+                                                struct wpa_supplicant *wpa_s);
+
 DECLARE_ACCESSOR(wpas_dbus_getter_capabilities);
 DECLARE_ACCESSOR(wpas_dbus_getter_state);
 DECLARE_ACCESSOR(wpas_dbus_getter_scanning);