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. Signed-off-by: Damien Dejean <damiendejean@xxxxxxxxxxxx> --- tests/hwsim/test_dbus.py | 45 ++++ wpa_supplicant/ctrl_iface.c | 55 +---- wpa_supplicant/dbus/dbus_new.c | 23 ++ wpa_supplicant/dbus/dbus_new.h | 4 + wpa_supplicant/dbus/dbus_new_handlers.c | 266 ++++++++++++++++++++++++ wpa_supplicant/dbus/dbus_new_handlers.h | 14 ++ wpa_supplicant/wpa_supplicant.c | 73 +++++++ wpa_supplicant/wpa_supplicant_i.h | 4 + 8 files changed, 433 insertions(+), 51 deletions(-) diff --git a/tests/hwsim/test_dbus.py b/tests/hwsim/test_dbus.py index 1143802c6..4edd0fd73 100644 --- a/tests/hwsim/test_dbus.py +++ b/tests/hwsim/test_dbus.py @@ -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") diff --git a/wpa_supplicant/ctrl_iface.c b/wpa_supplicant/ctrl_iface.c index 90f3e9fe9..b271a2292 100644 --- a/wpa_supplicant/ctrl_iface.c +++ b/wpa_supplicant/ctrl_iface.c @@ -3793,47 +3793,6 @@ static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s, } -static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s, - struct wpa_cred *cred) -{ - struct wpa_ssid *ssid; - char str[20]; - int id; - - if (cred == NULL) { - wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); - return -1; - } - - id = cred->id; - if (wpa_config_remove_cred(wpa_s->conf, id) < 0) { - wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred"); - return -1; - } - - wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id); - - /* Remove any network entry created based on the removed credential */ - ssid = wpa_s->conf->ssid; - while (ssid) { - if (ssid->parent_cred == cred) { - int res; - - wpa_printf(MSG_DEBUG, "Remove network id %d since it " - "used the removed credential", ssid->id); - res = os_snprintf(str, sizeof(str), "%d", ssid->id); - if (os_snprintf_error(sizeof(str), res)) - str[sizeof(str) - 1] = '\0'; - ssid = ssid->next; - wpa_supplicant_ctrl_iface_remove_network(wpa_s, str); - } else - ssid = ssid->next; - } - - return 0; -} - - static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, char *cmd) { @@ -3844,13 +3803,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, * "provisioning_sp=<FQDN> */ if (os_strcmp(cmd, "all") == 0) { wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all"); - cred = wpa_s->conf->cred; - while (cred) { - prev = cred; - cred = cred->next; - wpas_ctrl_remove_cred(wpa_s, prev); - } - return 0; + return wpa_supplicant_remove_all_creds(wpa_s); } if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) { @@ -3866,7 +3819,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, if (os_strcmp(prev->domain[i], cmd + 8) != 0) continue; - wpas_ctrl_remove_cred(wpa_s, prev); + wpa_supplicant_remove_cred(wpa_s, prev); break; } } @@ -3883,7 +3836,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, cred = cred->next; if (prev->provisioning_sp && os_strcmp(prev->provisioning_sp, cmd + 16) == 0) - wpas_ctrl_remove_cred(wpa_s, prev); + wpa_supplicant_remove_cred(wpa_s, prev); } return 0; } @@ -3892,7 +3845,7 @@ static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s, wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id); cred = wpa_config_get_cred(wpa_s->conf, id); - return wpas_ctrl_remove_cred(wpa_s, cred); + return wpa_supplicant_remove_cred(wpa_s, cred); } diff --git a/wpa_supplicant/dbus/dbus_new.c b/wpa_supplicant/dbus/dbus_new.c index 2c01943f7..bfa49d654 100644 --- a/wpa_supplicant/dbus/dbus_new.c +++ b/wpa_supplicant/dbus/dbus_new.c @@ -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 } } }; diff --git a/wpa_supplicant/dbus/dbus_new.h b/wpa_supplicant/dbus/dbus_new.h index 42db3892e..8ae0afeaa 100644 --- a/wpa_supplicant/dbus/dbus_new.h +++ b/wpa_supplicant/dbus/dbus_new.h @@ -16,6 +16,7 @@ struct wpa_global; struct wpa_supplicant; struct wpa_ssid; +struct wpa_cred; struct wps_event_m2d; struct wps_event_fail; struct wps_credential; @@ -96,6 +97,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" diff --git a/wpa_supplicant/dbus/dbus_new_handlers.c b/wpa_supplicant/dbus/dbus_new_handlers.c index db9f30c9a..c1abff94c 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.c +++ b/wpa_supplicant/dbus/dbus_new_handlers.c @@ -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 set of + * crendentials. + * @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 + */ +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 == NULL) + 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 == NULL) + 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 == NULL) + goto error; + } + } else if (entry.type == DBUS_TYPE_UINT32) { + value = os_zalloc(size); + if (value == NULL) + 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 == NULL) + 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 @@ -1514,6 +1621,165 @@ DBusMessage * wpas_dbus_handler_abort_scan(DBusMessage *message, return NULL; } +/** + * wpas_dbus_new_iface_add_cred - Add a new set of credentials + * @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 == NULL) { + wpa_printf(MSG_ERROR, "%s[dbus]: can't add new interface.", + __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 == NULL) { + 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 set of credentials + * @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; + int result; + + 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 == NULL || cred_id == NULL || !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 credentials"); + goto out; + } + + result = wpa_supplicant_remove_cred(wpa_s, cred); + if (result == -1) { + 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 sets of + * 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 = wpa_supplicant_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 diff --git a/wpa_supplicant/dbus/dbus_new_handlers.h b/wpa_supplicant/dbus/dbus_new_handlers.h index c36383f05..8a9f26a7e 100644 --- a/wpa_supplicant/dbus/dbus_new_handlers.h +++ b/wpa_supplicant/dbus/dbus_new_handlers.h @@ -144,6 +144,20 @@ DBusMessage * wpas_dbus_handler_eap_logoff(DBusMessage *message, DBusMessage * wpas_dbus_handler_eap_logon(DBusMessage *message, struct wpa_supplicant *wpa_s); +dbus_bool_t set_cred_properties(struct wpa_supplicant *wpa_s, + struct wpa_cred *cred, + DBusMessageIter *iter, + DBusError *error); + +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); diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c index b80f1d4f0..34da9cac4 100644 --- a/wpa_supplicant/wpa_supplicant.c +++ b/wpa_supplicant/wpa_supplicant.c @@ -4512,6 +4512,79 @@ void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, } +/** + * wpa_supplicant_remove_cred - Remove the set of provided credentials and all + * the network entries created based on the removed credentials. + * @wpa_s: wpa_supplicant structure for a network interface + * @cred: the set of credentials to remove + */ +int wpa_supplicant_remove_cred(struct wpa_supplicant* wpa_s, + struct wpa_cred* cred) +{ + struct wpa_ssid *ssid; + int id; + + if (cred == NULL) { + wpa_printf(MSG_DEBUG, "Could not find cred"); + return -1; + } + + id = cred->id; + if (wpa_config_remove_cred(wpa_s->conf, id) < 0) { + wpa_printf(MSG_DEBUG, "Could not find cred %d", id); + return -1; + } + + wpa_msg(wpa_s, MSG_INFO, CRED_REMOVED "%d", id); + + /* Remove any network entry created based on the removed credential */ + ssid = wpa_s->conf->ssid; + while (ssid) { + if (ssid->parent_cred == cred) { + int res; + wpa_printf(MSG_DEBUG, "Remove network id %d since it " + "used the removed credential", ssid->id); + res = wpa_supplicant_remove_network(wpa_s, ssid->id); + if (res == -1) { + wpa_printf(MSG_DEBUG, + "Could not find network id=%d", + ssid->id); + } + ssid = ssid->next; + } else + ssid = ssid->next; + } + + return 0; +} + + +/** + * wpa_supplicant_remove_cred - Remove all the interworking credentials. + * @wpa_s: wpa_supplicant structure for a network interface + */ +int wpa_supplicant_remove_all_creds(struct wpa_supplicant* wpa_s) +{ + int res; + struct wpa_cred *cred, *prev; + + cred = wpa_s->conf->cred; + while (cred) { + prev = cred; + cred = cred->next; + res = wpa_supplicant_remove_cred(wpa_s, prev); + if (res < 0) { + wpa_printf(MSG_DEBUG, "Remove all credentials failed " + "because remove of credential id=%d failed", + prev->id); + return -1; + } + } + + return 0; +} + + /** * wpas_set_pkcs11_engine_and_module_path - Set PKCS #11 engine and module path * @wpa_s: wpa_supplicant structure for a network interface diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h index cbc955159..d68350ae9 100644 --- a/wpa_supplicant/wpa_supplicant_i.h +++ b/wpa_supplicant/wpa_supplicant_i.h @@ -38,6 +38,7 @@ struct wpa_bss; struct wpa_scan_results; struct hostapd_hw_modes; struct wpa_driver_associate_params; +struct wpa_cred; /* * Forward declarations of private structures used within the ctrl_iface @@ -1578,6 +1579,9 @@ void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid); +int wpa_supplicant_remove_cred(struct wpa_supplicant* wpa_s, + struct wpa_cred* cred); +int wpa_supplicant_remove_all_creds(struct wpa_supplicant* wpa_s); int wpas_set_pkcs11_engine_and_module_path(struct wpa_supplicant *wpa_s, const char *pkcs11_engine_path, const char *pkcs11_module_path); -- 2.34.1.400.ga245620fadb-goog _______________________________________________ Hostap mailing list Hostap@xxxxxxxxxxxxxxxxxxx http://lists.infradead.org/mailman/listinfo/hostap