WPS: Clear WPS data on init failure
authorJouni Malinen <jouni@qca.qualcomm.com>
Thu, 20 Mar 2014 15:01:37 +0000 (17:01 +0200)
committerJouni Malinen <j@w1.fi>
Fri, 21 Mar 2014 11:23:23 +0000 (13:23 +0200)
It was possible for hapd->wps_beacon_ie and hapd->wps_probe_resp_ie to
be set if WPS initialization in hostapd failed after having set these
parameters (e.g., during UPnP configuration). In addition, many of the
other WPS configuration parameters that were allocated during the first
part of the initialization were not properly freed on error paths.

Signed-off-by: Jouni Malinen <jouni@qca.qualcomm.com>
src/ap/wps_hostapd.c

index 3a40125..62cd03c 100644 (file)
@@ -40,6 +40,7 @@ static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
                                    const u8 *ie, size_t ie_len,
                                    int ssi_signal);
 static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
+static void hostapd_wps_nfc_clear(struct wps_context *wps);
 
 
 struct wps_for_each_data {
@@ -897,7 +898,7 @@ static int hostapd_wps_rf_band_cb(void *ctx)
 }
 
 
-static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
+static void hostapd_wps_clear_ies(struct hostapd_data *hapd, int deinit_only)
 {
        wpabuf_free(hapd->wps_beacon_ie);
        hapd->wps_beacon_ie = NULL;
@@ -905,6 +906,9 @@ static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
        wpabuf_free(hapd->wps_probe_resp_ie);
        hapd->wps_probe_resp_ie = NULL;
 
+       if (deinit_only)
+               return;
+
        hostapd_set_ap_wps_ie(hapd);
 }
 
@@ -987,6 +991,21 @@ static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
 }
 
 
+static void hostapd_free_wps(struct wps_context *wps)
+{
+       int i;
+
+       for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+               wpabuf_free(wps->dev.vendor_ext[i]);
+       wps_device_data_free(&wps->dev);
+       os_free(wps->network_key);
+       hostapd_wps_nfc_clear(wps);
+       wpabuf_free(wps->dh_pubkey);
+       wpabuf_free(wps->dh_privkey);
+       os_free(wps);
+}
+
+
 int hostapd_init_wps(struct hostapd_data *hapd,
                     struct hostapd_bss_config *conf)
 {
@@ -994,7 +1013,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
        struct wps_registrar_config cfg;
 
        if (conf->wps_state == 0) {
-               hostapd_wps_clear_ies(hapd);
+               hostapd_wps_clear_ies(hapd, 0);
                return 0;
        }
 
@@ -1062,10 +1081,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
        os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
                  WPS_DEV_TYPE_LEN);
 
-       if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) {
-               os_free(wps);
-               return -1;
-       }
+       if (hostapd_wps_set_vendor_ext(hapd, wps) < 0)
+               goto fail;
 
        wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
 
@@ -1125,19 +1142,15 @@ int hostapd_init_wps(struct hostapd_data *hapd,
                wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
        } else if (conf->ssid.wpa_psk) {
                wps->network_key = os_malloc(2 * PMK_LEN + 1);
-               if (wps->network_key == NULL) {
-                       os_free(wps);
-                       return -1;
-               }
+               if (wps->network_key == NULL)
+                       goto fail;
                wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
                                 conf->ssid.wpa_psk->psk, PMK_LEN);
                wps->network_key_len = 2 * PMK_LEN;
        } else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
                wps->network_key = os_malloc(conf->ssid.wep.len[0]);
-               if (wps->network_key == NULL) {
-                       os_free(wps);
-                       return -1;
-               }
+               if (wps->network_key == NULL)
+                       goto fail;
                os_memcpy(wps->network_key, conf->ssid.wep.key[0],
                          conf->ssid.wep.len[0]);
                wps->network_key_len = conf->ssid.wep.len[0];
@@ -1183,9 +1196,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
        wps->registrar = wps_registrar_init(wps, &cfg);
        if (wps->registrar == NULL) {
                wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar");
-               os_free(wps->network_key);
-               os_free(wps);
-               return -1;
+               goto fail;
        }
 
 #ifdef CONFIG_WPS_UPNP
@@ -1201,6 +1212,10 @@ int hostapd_init_wps(struct hostapd_data *hapd,
        hapd->wps = wps;
 
        return 0;
+
+fail:
+       hostapd_free_wps(wps);
+       return -1;
 }
 
 
@@ -1215,8 +1230,7 @@ int hostapd_init_wps_complete(struct hostapd_data *hapd)
        if (hostapd_wps_upnp_init(hapd, wps) < 0) {
                wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
                wps_registrar_deinit(wps->registrar);
-               os_free(wps->network_key);
-               os_free(wps);
+               hostapd_free_wps(wps);
                hapd->wps = NULL;
                return -1;
        }
@@ -1246,21 +1260,18 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
        eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
        eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
        eloop_cancel_timeout(wps_reload_config, hapd->iface, NULL);
-       if (hapd->wps == NULL)
+       if (hapd->wps == NULL) {
+               hostapd_wps_clear_ies(hapd, 1);
                return;
+       }
 #ifdef CONFIG_WPS_UPNP
        hostapd_wps_upnp_deinit(hapd);
 #endif /* CONFIG_WPS_UPNP */
        wps_registrar_deinit(hapd->wps->registrar);
-       os_free(hapd->wps->network_key);
-       wps_device_data_free(&hapd->wps->dev);
-       wpabuf_free(hapd->wps->dh_pubkey);
-       wpabuf_free(hapd->wps->dh_privkey);
        wps_free_pending_msgs(hapd->wps->upnp_msgs);
-       hostapd_wps_nfc_clear(hapd->wps);
-       os_free(hapd->wps);
+       hostapd_free_wps(hapd->wps);
        hapd->wps = NULL;
-       hostapd_wps_clear_ies(hapd);
+       hostapd_wps_clear_ies(hapd, 1);
 }