diff --git a/hostapd/config.c b/hostapd/config.c index 22cef55a2..dbdee76df 100644 --- a/hostapd/config.c +++ b/hostapd/config.c @@ -2158,6 +2158,7 @@ struct hostapd_config * hostapd_config_read(const char *fname) errors++; } } else if (os_strcmp(buf, "wps_pin_requests") == 0) { + os_free(bss->wps_pin_requests); bss->wps_pin_requests = os_strdup(pos); } else if (os_strcmp(buf, "device_name") == 0) { if (os_strlen(pos) > 32) { @@ -2165,6 +2166,7 @@ struct hostapd_config * hostapd_config_read(const char *fname) "device_name", line); errors++; } + os_free(bss->device_name); bss->device_name = os_strdup(pos); } else if (os_strcmp(buf, "manufacturer") == 0) { if (os_strlen(pos) > 64) { @@ -2172,6 +2174,7 @@ struct hostapd_config * hostapd_config_read(const char *fname) "manufacturer", line); errors++; } + os_free(bss->manufacturer); bss->manufacturer = os_strdup(pos); } else if (os_strcmp(buf, "model_name") == 0) { if (os_strlen(pos) > 32) { @@ -2179,6 +2182,7 @@ struct hostapd_config * hostapd_config_read(const char *fname) "model_name", line); errors++; } + os_free(bss->model_name); bss->model_name = os_strdup(pos); } else if (os_strcmp(buf, "model_number") == 0) { if (os_strlen(pos) > 32) { @@ -2186,6 +2190,7 @@ struct hostapd_config * hostapd_config_read(const char *fname) "model_number", line); errors++; } + os_free(bss->model_number); bss->model_number = os_strdup(pos); } else if (os_strcmp(buf, "serial_number") == 0) { if (os_strlen(pos) > 32) { @@ -2193,10 +2198,13 @@ struct hostapd_config * hostapd_config_read(const char *fname) "serial_number", line); errors++; } + os_free(bss->serial_number); bss->serial_number = os_strdup(pos); } else if (os_strcmp(buf, "device_type") == 0) { + os_free(bss->device_type); bss->device_type = os_strdup(pos); } else if (os_strcmp(buf, "config_methods") == 0) { + os_free(bss->config_methods); bss->config_methods = os_strdup(pos); } else if (os_strcmp(buf, "os_version") == 0) { if (hexstr2bin(pos, bss->os_version, 4)) { @@ -2205,7 +2213,20 @@ struct hostapd_config * hostapd_config_read(const char *fname) errors++; } } else if (os_strcmp(buf, "ap_pin") == 0) { + os_free(bss->ap_pin); bss->ap_pin = os_strdup(pos); + } else if (os_strcmp(buf, "skip_cred_build") == 0) { + bss->skip_cred_build = atoi(pos); + } else if (os_strcmp(buf, "extra_cred") == 0) { + os_free(bss->extra_cred); + bss->extra_cred = + (u8 *) os_readfile(pos, &bss->extra_cred_len); + if (bss->extra_cred == NULL) { + wpa_printf(MSG_ERROR, "Line %d: could not " + "read Credentials from '%s'", + line, pos); + errors++; + } #endif /* CONFIG_WPS */ } else { wpa_printf(MSG_ERROR, "Line %d: unknown configuration " diff --git a/hostapd/config.h b/hostapd/config.h index c9c715c92..0896749b0 100644 --- a/hostapd/config.h +++ b/hostapd/config.h @@ -300,6 +300,9 @@ struct hostapd_bss_config { char *config_methods; u8 os_version[4]; char *ap_pin; + int skip_cred_build; + u8 *extra_cred; + size_t extra_cred_len; #endif /* CONFIG_WPS */ }; diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf index c5d82e6ba..853bc6e57 100644 --- a/hostapd/hostapd.conf +++ b/hostapd/hostapd.conf @@ -934,6 +934,20 @@ own_ip_addr=127.0.0.1 # access point. #ap_pin=12345670 +# Skip building of automatic WPS credential +# This can be used to allow the automatically generated Credential attribute to +# be replaced with pre-configured Credential(s). +#skip_cred_build=1 + +# Additional Credential attribute(s) +# This option can be used to add pre-configured Credential attributes into M8 +# message when acting as a Registrar. If skip_cred_build=1, this data will also +# be able to override the Credential attribute that would have otherwise been +# automatically generated based on network configuration. This configuration +# option points to an external file that much contain the WPS Credential +# attribute(s) as binary data. +#extra_cred=hostapd.cred + ##### Multiple BSSID support ################################################## # diff --git a/hostapd/wps_hostapd.c b/hostapd/wps_hostapd.c index 74c2d887d..0a0b7cefc 100644 --- a/hostapd/wps_hostapd.c +++ b/hostapd/wps_hostapd.c @@ -516,6 +516,9 @@ int hostapd_init_wps(struct hostapd_data *hapd, cfg.set_ie_cb = hostapd_wps_set_ie_cb; cfg.pin_needed_cb = hostapd_wps_pin_needed_cb; cfg.cb_ctx = hapd; + cfg.skip_cred_build = conf->skip_cred_build; + cfg.extra_cred = conf->extra_cred; + cfg.extra_cred_len = conf->extra_cred_len; wps->registrar = wps_registrar_init(wps, &cfg); if (wps->registrar == NULL) { diff --git a/src/wps/wps.h b/src/wps/wps.h index 52d7903cb..b275cfd0d 100644 --- a/src/wps/wps.h +++ b/src/wps/wps.h @@ -204,6 +204,31 @@ struct wps_registrar_config { * cb_ctx: Higher layer context data for Registrar callbacks */ void *cb_ctx; + + /** + * skip_cred_build: Do not build credential + * + * This option can be used to disable internal code that builds + * Credential attribute into M8 based on the current network + * configuration and Enrollee capabilities. The extra_cred data will + * then be used as the Credential(s). + */ + int skip_cred_build; + + /** + * extra_cred: Additional Credential attribute(s) + * + * This optional data (set to %NULL to disable) can be used to add + * Credential attribute(s) for other networks into M8. If + * skip_cred_build is set, this will also override the automatically + * generated Credential attribute. + */ + const u8 *extra_cred; + + /** + * extra_cred_len: Length of extra_cred in octets + */ + size_t extra_cred_len; }; diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c index 7e9fccfb2..771660944 100644 --- a/src/wps/wps_registrar.c +++ b/src/wps/wps_registrar.c @@ -89,6 +89,9 @@ struct wps_registrar { struct wps_uuid_pin *pins; struct wps_pbc_session *pbc_sessions; + + int skip_cred_build; + struct wpabuf *extra_cred; }; @@ -323,6 +326,15 @@ wps_registrar_init(struct wps_context *wps, reg->set_ie_cb = cfg->set_ie_cb; reg->pin_needed_cb = cfg->pin_needed_cb; reg->cb_ctx = cfg->cb_ctx; + reg->skip_cred_build = cfg->skip_cred_build; + if (cfg->extra_cred) { + reg->extra_cred = wpabuf_alloc_copy(cfg->extra_cred, + cfg->extra_cred_len); + if (reg->extra_cred == NULL) { + os_free(reg); + return NULL; + } + } if (wps_set_ie(reg)) { wps_registrar_deinit(reg); @@ -344,6 +356,7 @@ void wps_registrar_deinit(struct wps_registrar *reg) eloop_cancel_timeout(wps_registrar_pbc_timeout, reg, NULL); wps_free_pins(reg->pins); wps_free_pbc_sessions(reg->pbc_sessions); + wpabuf_free(reg->extra_cred); os_free(reg); } @@ -918,6 +931,9 @@ static int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) { struct wpabuf *cred; + if (wps->wps->registrar->skip_cred_build) + goto skip_cred_build; + wpa_printf(MSG_DEBUG, "WPS: * Credential"); os_memset(&wps->cred, 0, sizeof(wps->cred)); @@ -1021,6 +1037,12 @@ static int wps_build_cred(struct wps_data *wps, struct wpabuf *msg) wpabuf_put_buf(msg, cred); wpabuf_free(cred); +skip_cred_build: + if (wps->wps->registrar->extra_cred) { + wpa_printf(MSG_DEBUG, "WPS: * Credential (pre-configured)"); + wpabuf_put_buf(msg, wps->wps->registrar->extra_cred); + } + return 0; }