From 476621644cd3eb94f329bda755f3c639239d321c Mon Sep 17 00:00:00 2001 From: Jouni Malinen Date: Sun, 18 Jan 2009 12:27:12 +0200 Subject: [PATCH] WPS: Add configurable option for processing credentials externally The wps_cred_process option can be used to configure wpa_supplicant to send received Credential attributes for external processing over ctrl_iface and dbus. This allows external programs to update their configuration when WPS is used to provision new networks. --- wpa_supplicant/config.h | 11 ++++++ wpa_supplicant/config_file.c | 4 +++ wpa_supplicant/config_winreg.c | 4 +++ wpa_supplicant/ctrl_iface_dbus.c | 58 ++++++++++++++++++++++++++++++ wpa_supplicant/ctrl_iface_dbus.h | 10 ++++++ wpa_supplicant/wpa_supplicant.conf | 7 ++++ wpa_supplicant/wps_supplicant.c | 28 ++++++++++++++- 7 files changed, 121 insertions(+), 1 deletion(-) diff --git a/wpa_supplicant/config.h b/wpa_supplicant/config.h index 0cea4dc99..4484e91d9 100644 --- a/wpa_supplicant/config.h +++ b/wpa_supplicant/config.h @@ -312,6 +312,17 @@ struct wpa_config { * in */ char country[2]; + + /** + * wps_cred_processing - Credential processing + * + * 0 = process received credentials internally + * 1 = do not process received credentials; just pass them over + * ctrl_iface to external program(s) + * 2 = process received credentials internally and pass them over + * ctrl_iface to external program(s) + */ + int wps_cred_processing; }; diff --git a/wpa_supplicant/config_file.c b/wpa_supplicant/config_file.c index f544a56de..29e494c1e 100644 --- a/wpa_supplicant/config_file.c +++ b/wpa_supplicant/config_file.c @@ -456,6 +456,7 @@ static const struct global_parse_data global_fields[] = { { STR_RANGE(serial_number, 0, 32) }, { STR(device_type) }, { FUNC(os_version) }, + { INT_RANGE(wps_cred_processing, 0, 2) }, #endif /* CONFIG_WPS */ { FUNC(country) } }; @@ -881,6 +882,9 @@ static void wpa_config_write_global(FILE *f, struct wpa_config *config) if (WPA_GET_BE32(config->os_version)) fprintf(f, "os_version=%08x\n", WPA_GET_BE32(config->os_version)); + if (config->wps_cred_processing) + fprintf(f, "wps_cred_processing=%d\n", + config->wps_cred_processing); #endif /* CONFIG_WPS */ if (config->country[0] && config->country[1]) { fprintf(f, "country=%c%c\n", diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c index 01996429a..456d41792 100644 --- a/wpa_supplicant/config_winreg.c +++ b/wpa_supplicant/config_winreg.c @@ -251,6 +251,8 @@ static int wpa_config_read_global(struct wpa_config *config, HKEY hk) hk, TEXT("device_type")); if (wpa_config_read_global_os_version(config, hk)) errors++; + wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"), + &config->wps_cred_processing); #endif /* CONFIG_WPS */ return errors ? -1 : 0; @@ -573,6 +575,8 @@ static int wpa_config_write_global(struct wpa_config *config, HKEY hk) WPA_GET_BE32(config->os_version)); wpa_config_write_reg_string(hk, "os_version", vbuf); } + wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"), + config->wps_cred_processing, 0); #endif /* CONFIG_WPS */ return 0; diff --git a/wpa_supplicant/ctrl_iface_dbus.c b/wpa_supplicant/ctrl_iface_dbus.c index 7f2fba4ab..b772247cc 100644 --- a/wpa_supplicant/ctrl_iface_dbus.c +++ b/wpa_supplicant/ctrl_iface_dbus.c @@ -18,6 +18,7 @@ #include "eloop.h" #include "config.h" #include "wpa_supplicant_i.h" +#include "wps/wps.h" #include "ctrl_iface_dbus.h" #include "ctrl_iface_dbus_handlers.h" @@ -738,6 +739,63 @@ out: } +#ifdef CONFIG_WPS +void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ + struct ctrl_iface_dbus_priv *iface; + DBusMessage *_signal = NULL; + const char *path; + + /* Do nothing if the control interface is not turned on */ + if (wpa_s->global == NULL) + return; + iface = wpa_s->global->dbus_ctrl_iface; + if (iface == NULL) + return; + + path = wpa_supplicant_get_dbus_path(wpa_s); + if (path == NULL) { + perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "interface didn't have a dbus path"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "interface didn't have a dbus path; can't send " + "signal."); + return; + } + _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE, + "WpsCred"); + if (_signal == NULL) { + perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "couldn't create dbus signal; likely out of memory"); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "couldn't create dbus signal; likely out of " + "memory."); + return; + } + + if (!dbus_message_append_args(_signal, + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + &cred->cred_attr, cred->cred_attr_len, + DBUS_TYPE_INVALID)) { + perror("wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "not enough memory to construct signal."); + wpa_printf(MSG_ERROR, + "wpa_supplicant_dbus_notify_wps_cred[dbus]: " + "not enough memory to construct signal."); + goto out; + } + + dbus_connection_send(iface->con, _signal, NULL); + +out: + dbus_message_unref(_signal); +} +#endif /* CONFIG_WPS */ + + /** * integrate_with_eloop - Register our mainloop integration with dbus * @connection: connection to the system message bus diff --git a/wpa_supplicant/ctrl_iface_dbus.h b/wpa_supplicant/ctrl_iface_dbus.h index b66c179c5..68919de02 100644 --- a/wpa_supplicant/ctrl_iface_dbus.h +++ b/wpa_supplicant/ctrl_iface_dbus.h @@ -15,6 +15,8 @@ #ifndef CTRL_IFACE_DBUS_H #define CTRL_IFACE_DBUS_H +struct wps_credential; + #ifdef CONFIG_CTRL_IFACE_DBUS #ifndef SIGPOLL @@ -84,6 +86,8 @@ void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s); void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, wpa_states new_state, wpa_states old_state); +void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred); char * wpas_dbus_decompose_object_path(const char *path, char **network, char **bssid); @@ -129,6 +133,12 @@ wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s, { } +static inline void +wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s, + const struct wps_credential *cred) +{ +} + static inline int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s) { diff --git a/wpa_supplicant/wpa_supplicant.conf b/wpa_supplicant/wpa_supplicant.conf index cfcea8831..4b1f90b60 100644 --- a/wpa_supplicant/wpa_supplicant.conf +++ b/wpa_supplicant/wpa_supplicant.conf @@ -190,6 +190,13 @@ fast_reauth=1 # 4-octet operating system version number (hex string) #os_version=01020300 +# Credential processing +# 0 = process received credentials internally (default) +# 1 = do not process received credentials; just pass them over ctrl_iface to +# external program(s) +# 2 = process received credentials internally and pass them over ctrl_iface +# to external program(s) +#wps_cred_processing=0 # network block # diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c index fb1d83322..14f1f86ff 100644 --- a/wpa_supplicant/wps_supplicant.c +++ b/wpa_supplicant/wps_supplicant.c @@ -23,6 +23,7 @@ #include "eloop.h" #include "uuid.h" #include "wpa_ctrl.h" +#include "ctrl_iface_dbus.h" #include "eap_common/eap_wsc_common.h" #include "wps_supplicant.h" @@ -46,6 +47,15 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s) return 1; } + if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS && wpa_s->current_ssid) { + wpa_printf(MSG_DEBUG, "WPS: Registration completed - waiting " + "for external credential processing"); + wpas_clear_wps(wpa_s); + wpa_supplicant_deauthenticate(wpa_s, + WLAN_REASON_DEAUTH_LEAVING); + return 1; + } + return 0; } @@ -56,11 +66,27 @@ static int wpa_supplicant_wps_cred(void *ctx, struct wpa_supplicant *wpa_s = ctx; struct wpa_ssid *ssid = wpa_s->current_ssid; - wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED); + if ((wpa_s->conf->wps_cred_processing == 1 || + wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) { + size_t blen = cred->cred_attr_len * 2 + 1; + char *buf = os_malloc(blen); + if (buf) { + wpa_snprintf_hex(buf, blen, + cred->cred_attr, cred->cred_attr_len); + wpa_msg(wpa_s, MSG_INFO, "%s%s", + WPS_EVENT_CRED_RECEIVED, buf); + os_free(buf); + } + wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred); + } else + wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_CRED_RECEIVED); wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute", cred->cred_attr, cred->cred_attr_len); + if (wpa_s->conf->wps_cred_processing == 1) + return 0; + if (cred->auth_type != WPS_AUTH_OPEN && cred->auth_type != WPS_AUTH_SHARED && cred->auth_type != WPS_AUTH_WPAPSK &&