diff options
Diffstat (limited to 'wpa_supplicant/config.c')
-rw-r--r-- | wpa_supplicant/config.c | 305 |
1 files changed, 192 insertions, 113 deletions
diff --git a/wpa_supplicant/config.c b/wpa_supplicant/config.c index b89732dd..be210297 100644 --- a/wpa_supplicant/config.c +++ b/wpa_supplicant/config.c @@ -53,42 +53,6 @@ struct parse_data { }; -static char * wpa_config_parse_string(const char *value, size_t *len) -{ - if (*value == '"') { - const char *pos; - char *str; - value++; - pos = os_strrchr(value, '"'); - if (pos == NULL || pos[1] != '\0') - return NULL; - *len = pos - value; - str = os_malloc(*len + 1); - if (str == NULL) - return NULL; - os_memcpy(str, value, *len); - str[*len] = '\0'; - return str; - } else { - u8 *str; - size_t tlen, hlen = os_strlen(value); - if (hlen & 1) - return NULL; - tlen = hlen / 2; - str = os_malloc(tlen + 1); - if (str == NULL) - return NULL; - if (hexstr2bin(value, str, tlen)) { - os_free(str); - return NULL; - } - str[tlen] = '\0'; - *len = tlen; - return (char *) str; - } -} - - static int wpa_config_parse_str(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) @@ -149,18 +113,6 @@ set: #ifndef NO_CONFIG_WRITE -static int is_hex(const u8 *data, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) { - if (data[i] < 32 || data[i] >= 127) - return 1; - } - return 0; -} - - static char * wpa_config_write_string_ascii(const u8 *value, size_t len) { char *buf; @@ -219,26 +171,6 @@ static char * wpa_config_write_str(const struct parse_data *data, return wpa_config_write_string((const u8 *) *src, len); } - -#ifdef WPA_UNICODE_SSID -static char * wpa_config_write_str_unicode(const struct parse_data *data, - struct wpa_ssid *ssid) -{ - size_t len; - char **src; - - src = (char **) (((u8 *) ssid) + (long) data->param1); - if (*src == NULL) - return NULL; - - if (data->param2) - len = *((size_t *) (((u8 *) ssid) + (long) data->param2)); - else - len = os_strlen(*src); - - return wpa_config_write_string_ascii((const u8 *) *src, len); -} -#endif #endif /* NO_CONFIG_WRITE */ @@ -344,6 +276,21 @@ static int wpa_config_parse_psk(const struct parse_data *data, struct wpa_ssid *ssid, int line, const char *value) { +#ifdef CONFIG_EXT_PASSWORD + if (os_strncmp(value, "ext:", 4) == 0) { + os_free(ssid->passphrase); + ssid->passphrase = NULL; + ssid->psk_set = 0; + os_free(ssid->ext_psk); + ssid->ext_psk = os_strdup(value + 4); + if (ssid->ext_psk == NULL) + return -1; + wpa_printf(MSG_DEBUG, "PSK: External password '%s'", + ssid->ext_psk); + return 0; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (*value == '"') { #ifndef CONFIG_NO_PBKDF2 const char *pos; @@ -401,6 +348,17 @@ static int wpa_config_parse_psk(const struct parse_data *data, static char * wpa_config_write_psk(const struct parse_data *data, struct wpa_ssid *ssid) { +#ifdef CONFIG_EXT_PASSWORD + if (ssid->ext_psk) { + size_t len = 4 + os_strlen(ssid->ext_psk) + 1; + char *buf = os_malloc(len); + if (buf == NULL) + return NULL; + os_snprintf(buf, len, "ext:%s", ssid->ext_psk); + return buf; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (ssid->passphrase) return wpa_config_write_string_ascii( (const u8 *) ssid->passphrase, @@ -685,6 +643,8 @@ static int wpa_config_parse_cipher(int line, const char *value) *end = '\0'; if (os_strcmp(start, "CCMP") == 0) val |= WPA_CIPHER_CCMP; + else if (os_strcmp(start, "GCMP") == 0) + val |= WPA_CIPHER_GCMP; else if (os_strcmp(start, "TKIP") == 0) val |= WPA_CIPHER_TKIP; else if (os_strcmp(start, "WEP104") == 0) @@ -736,6 +696,16 @@ static char * wpa_config_write_cipher(int cipher) pos += ret; } + if (cipher & WPA_CIPHER_GCMP) { + ret = os_snprintf(pos, end - pos, "%sGCMP", + pos == buf ? "" : " "); + if (ret < 0 || ret >= end - pos) { + end[-1] = '\0'; + return buf; + } + pos += ret; + } + if (cipher & WPA_CIPHER_TKIP) { ret = os_snprintf(pos, end - pos, "%sTKIP", pos == buf ? "" : " "); @@ -789,7 +759,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data, val = wpa_config_parse_cipher(line, value); if (val == -1) return -1; - if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) { + if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | + WPA_CIPHER_NONE)) { wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher " "(0x%x).", line, val); return -1; @@ -818,8 +789,8 @@ static int wpa_config_parse_group(const struct parse_data *data, val = wpa_config_parse_cipher(line, value); if (val == -1) return -1; - if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 | - WPA_CIPHER_WEP40)) { + if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP | + WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) { wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher " "(0x%x).", line, val); return -1; @@ -949,7 +920,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data, used = 0; len = 10; - freqs = os_zalloc((len + 1) * sizeof(int)); + freqs = os_calloc(len + 1, sizeof(int)); if (freqs == NULL) return NULL; @@ -960,7 +931,7 @@ static int * wpa_config_parse_freqs(const struct parse_data *data, if (used == len) { int *n; size_t i; - n = os_realloc(freqs, (len * 2 + 1) * sizeof(int)); + n = os_realloc_array(freqs, len * 2 + 1, sizeof(int)); if (n == NULL) { os_free(freqs); return NULL; @@ -1089,8 +1060,8 @@ static int wpa_config_parse_eap(const struct parse_data *data, last = *end == '\0'; *end = '\0'; tmp = methods; - methods = os_realloc(methods, - (num_methods + 1) * sizeof(*methods)); + methods = os_realloc_array(methods, num_methods + 1, + sizeof(*methods)); if (methods == NULL) { os_free(tmp); os_free(buf); @@ -1120,7 +1091,7 @@ static int wpa_config_parse_eap(const struct parse_data *data, os_free(buf); tmp = methods; - methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods)); + methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods)); if (methods == NULL) { os_free(tmp); return -1; @@ -1186,6 +1157,20 @@ static int wpa_config_parse_password(const struct parse_data *data, return 0; } +#ifdef CONFIG_EXT_PASSWORD + if (os_strncmp(value, "ext:", 4) == 0) { + char *name = os_strdup(value + 4); + if (name == NULL) + return -1; + os_free(ssid->eap.password); + ssid->eap.password = (u8 *) name; + ssid->eap.password_len = os_strlen(name); + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD; + return 0; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (os_strncmp(value, "hash:", 5) != 0) { char *tmp; size_t res_len; @@ -1203,6 +1188,7 @@ static int wpa_config_parse_password(const struct parse_data *data, ssid->eap.password = (u8 *) tmp; ssid->eap.password_len = res_len; ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } @@ -1231,6 +1217,7 @@ static int wpa_config_parse_password(const struct parse_data *data, ssid->eap.password = hash; ssid->eap.password_len = 16; ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH; + ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD; return 0; } @@ -1244,6 +1231,17 @@ static char * wpa_config_write_password(const struct parse_data *data, if (ssid->eap.password == NULL) return NULL; +#ifdef CONFIG_EXT_PASSWORD + if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) { + buf = os_zalloc(4 + ssid->eap.password_len + 1); + if (buf == NULL) + return NULL; + os_memcpy(buf, "ext:", 4); + os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len); + return buf; + } +#endif /* CONFIG_EXT_PASSWORD */ + if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) { return wpa_config_write_string( ssid->eap.password, ssid->eap.password_len); @@ -1391,18 +1389,27 @@ static int wpa_config_parse_p2p_client_list(const struct parse_data *data, pos++; if (hwaddr_aton(pos, addr)) { - wpa_printf(MSG_ERROR, "Line %d: Invalid " - "p2p_client_list address '%s'.", - line, value); - /* continue anyway */ + if (count == 0) { + wpa_printf(MSG_ERROR, "Line %d: Invalid " + "p2p_client_list address '%s'.", + line, value); + os_free(buf); + return -1; + } + /* continue anyway since this could have been from a + * truncated configuration file line */ + wpa_printf(MSG_INFO, "Line %d: Ignore likely " + "truncated p2p_client_list address '%s'", + line, pos); } else { - n = os_realloc(buf, (count + 1) * ETH_ALEN); + n = os_realloc_array(buf, count + 1, ETH_ALEN); if (n == NULL) { os_free(buf); return -1; } buf = n; - os_memcpy(buf + count * ETH_ALEN, addr, ETH_ALEN); + os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN); + os_memcpy(buf, addr, ETH_ALEN); count++; wpa_hexdump(MSG_MSGDUMP, "p2p_client_list", addr, ETH_ALEN); @@ -1436,10 +1443,10 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data, pos = value; end = value + 20 * ssid->num_p2p_clients; - for (i = 0; i < ssid->num_p2p_clients; i++) { + for (i = ssid->num_p2p_clients; i > 0; i--) { res = os_snprintf(pos, end - pos, MACSTR " ", MAC2STR(ssid->p2p_client_list + - i * ETH_ALEN)); + (i - 1) * ETH_ALEN)); if (res < 0 || res >= end - pos) { os_free(value); return NULL; @@ -1500,15 +1507,6 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data, OFFSET(f), (void *) 0 #define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \ OFFSET(eap.f), (void *) 0 -#ifdef WPA_UNICODE_SSID -/* STR_* variants that do not force conversion to ASCII */ -#define _STR_UNICODE(f) #f, wpa_config_parse_str, wpa_config_write_str_unicode, OFFSET(f) -#define STR_UNICODE(f) _STR_UNICODE(f), NULL, NULL, NULL, 0 -#define _STR_LEN_UNICODE(f) _STR_UNICODE(f), OFFSET(f ## _len) -#define STR_LEN_UNICODE(f) _STR_LEN_UNICODE(f), NULL, NULL, 0 -#define _STR_RANGE_UNICODE(f, min, max) _STR_LEN_UNICODE(f), (void *) (min), (void *) (max) -#define STR_RANGE_UNICODE(f, min, max) _STR_RANGE_UNICODE(f, min, max), 0 -#endif #endif /* NO_CONFIG_WRITE */ /* INT: Define an integer variable */ @@ -1553,11 +1551,7 @@ static char * wpa_config_write_p2p_client_list(const struct parse_data *data, * functions. */ static const struct parse_data ssid_fields[] = { -#ifdef WPA_UNICODE_SSID - { STR_RANGE_UNICODE(ssid, 0, MAX_SSID_LEN) }, -#else { STR_RANGE(ssid, 0, MAX_SSID_LEN) }, -#endif { INT_RANGE(scan_ssid, 0, 1) }, { FUNC(bssid) }, { FUNC_KEY(psk) }, @@ -1646,15 +1640,6 @@ static const struct parse_data ssid_fields[] = { { INT(dtim_period) }, }; -#ifdef WPA_UNICODE_SSID -#undef _STR_UNICODE -#undef STR_UNICODE -#undef _STR_LEN_UNICODE -#undef STR_LEN_UNICODE -#undef _STR_RANGE_UNICODE -#undef STR_RANGE_UNICODE -#endif - #undef OFFSET #undef _STR #undef STR @@ -1706,8 +1691,8 @@ int wpa_config_add_prio_network(struct wpa_config *config, } /* First network for this priority - add a new priority list */ - nlist = os_realloc(config->pssid, - (config->num_prio + 1) * sizeof(struct wpa_ssid *)); + nlist = os_realloc_array(config->pssid, config->num_prio + 1, + sizeof(struct wpa_ssid *)); if (nlist == NULL) return -1; @@ -1813,6 +1798,7 @@ void wpa_config_free_ssid(struct wpa_ssid *ssid) { os_free(ssid->ssid); os_free(ssid->passphrase); + os_free(ssid->ext_psk); #ifdef IEEE8021X_EAPOL eap_peer_config_free(&ssid->eap); #endif /* IEEE8021X_EAPOL */ @@ -1840,6 +1826,9 @@ void wpa_config_free_cred(struct wpa_cred *cred) os_free(cred->imsi); os_free(cred->milenage); os_free(cred->domain); + os_free(cred->eap_method); + os_free(cred->phase1); + os_free(cred->phase2); os_free(cred); } @@ -1905,6 +1894,7 @@ void wpa_config_free(struct wpa_config *config) wpabuf_free(config->wps_nfc_dh_pubkey); wpabuf_free(config->wps_nfc_dh_privkey); wpabuf_free(config->wps_nfc_dev_pw); + os_free(config->ext_password_backend); os_free(config); } @@ -2139,7 +2129,7 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys) get_keys = get_keys && ssid->export_keys; - props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1)); + props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *)); if (!props) return NULL; @@ -2267,8 +2257,7 @@ char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var) void wpa_config_update_psk(struct wpa_ssid *ssid) { #ifndef CONFIG_NO_PBKDF2 - pbkdf2_sha1(ssid->passphrase, - (char *) ssid->ssid, ssid->ssid_len, 4096, + pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096, ssid->psk, PMK_LEN); wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)", ssid->psk, PMK_LEN); @@ -2293,6 +2282,31 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "eap") == 0) { + struct eap_method_type method; + method.method = eap_peer_get_type(value, &method.vendor); + if (method.vendor == EAP_VENDOR_IETF && + method.method == EAP_TYPE_NONE) { + wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' " + "for a credential", line, value); + return -1; + } + os_free(cred->eap_method); + cred->eap_method = os_malloc(sizeof(*cred->eap_method)); + if (cred->eap_method == NULL) + return -1; + os_memcpy(cred->eap_method, &method, sizeof(method)); + return 0; + } + + if (os_strcmp(var, "password") == 0 && + os_strncmp(value, "ext:", 4) == 0) { + os_free(cred->password); + cred->password = os_strdup(value); + cred->ext_password = 1; + return 0; + } + val = wpa_config_parse_string(value, &len); if (val == NULL) { wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string " @@ -2315,6 +2329,7 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, if (os_strcmp(var, "password") == 0) { os_free(cred->password); cred->password = val; + cred->ext_password = 0; return 0; } @@ -2360,6 +2375,32 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var, return 0; } + if (os_strcmp(var, "phase1") == 0) { + os_free(cred->phase1); + cred->phase1 = val; + return 0; + } + + if (os_strcmp(var, "phase2") == 0) { + os_free(cred->phase2); + cred->phase2 = val; + return 0; + } + + if (os_strcmp(var, "roaming_consortium") == 0) { + if (len < 3 || len > sizeof(cred->roaming_consortium)) { + wpa_printf(MSG_ERROR, "Line %d: invalid " + "roaming_consortium length %d (3..15 " + "expected)", line, (int) len); + os_free(val); + return -1; + } + os_memcpy(cred->roaming_consortium, val, len); + cred->roaming_consortium_len = len; + os_free(val); + return 0; + } + if (line) { wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.", line, var); @@ -2530,6 +2571,15 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, const char *driver_param) { struct wpa_config *config; + const int aCWmin = 4, aCWmax = 10; + const struct hostapd_wmm_ac_params ac_bk = + { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */ + const struct hostapd_wmm_ac_params ac_be = + { aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */ + const struct hostapd_wmm_ac_params ac_vi = /* video traffic */ + { aCWmin - 1, aCWmin, 2, 3000 / 32, 0 }; + const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */ + { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 }; config = os_zalloc(sizeof(*config)); if (config == NULL) @@ -2539,11 +2589,16 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface, config->fast_reauth = DEFAULT_FAST_REAUTH; config->p2p_go_intent = DEFAULT_P2P_GO_INTENT; config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS; + config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY; config->bss_max_count = DEFAULT_BSS_MAX_COUNT; config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE; config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT; config->max_num_sta = DEFAULT_MAX_NUM_STA; config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE; + config->wmm_ac_params[0] = ac_be; + config->wmm_ac_params[1] = ac_bk; + config->wmm_ac_params[2] = ac_vi; + config->wmm_ac_params[3] = ac_vo; if (ctrl_interface) config->ctrl_interface = os_strdup(ctrl_interface); @@ -2836,7 +2891,8 @@ static int wpa_config_process_p2p_pref_chan( pos2++; chan = atoi(pos2); - n = os_realloc(pref, (num + 1) * sizeof(struct p2p_channel)); + n = os_realloc_array(pref, num + 1, + sizeof(struct p2p_channel)); if (n == NULL) goto fail; pref = n; @@ -2950,6 +3006,7 @@ static const struct global_parse_data global_fields[] = { { INT(bss_expiration_age), 0 }, { INT(bss_expiration_scan_count), 0 }, { INT_RANGE(filter_ssids, 0, 1), 0 }, + { INT_RANGE(filter_rssi, -100, 0), 0 }, { INT(max_num_sta), 0 }, { INT_RANGE(disassoc_low_ack, 0, 1), 0 }, #ifdef CONFIG_HS20 @@ -2963,7 +3020,10 @@ static const struct global_parse_data global_fields[] = { { INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 }, { BIN(wps_nfc_dh_pubkey), 0 }, { BIN(wps_nfc_dh_privkey), 0 }, - { BIN(wps_nfc_dev_pw), 0 } + { BIN(wps_nfc_dev_pw), 0 }, + { STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND }, + { INT(p2p_go_max_inactivity), 0 }, + { INT_RANGE(auto_interworking, 0, 1), 0 }, }; #undef FUNC @@ -2998,6 +3058,25 @@ int wpa_config_process_global(struct wpa_config *config, char *pos, int line) break; } if (i == NUM_GLOBAL_FIELDS) { +#ifdef CONFIG_AP + if (os_strncmp(pos, "wmm_ac_", 7) == 0) { + char *tmp = os_strchr(pos, '='); + if (tmp == NULL) { + if (line < 0) + return -1; + wpa_printf(MSG_ERROR, "Line %d: invalid line " + "'%s'", line, pos); + return -1; + } + *tmp++ = '\0'; + if (hostapd_config_wmm_ac(config->wmm_ac_params, pos, + tmp)) { + wpa_printf(MSG_ERROR, "Line %d: invalid WMM " + "AC item", line); + return -1; + } + } +#endif /* CONFIG_AP */ if (line < 0) return -1; wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.", |