Updated to hostap_2_6
[mech_eap.git] / libeap / wpa_supplicant / config.c
index b1adab7..dd922ca 100644 (file)
@@ -32,7 +32,11 @@ struct parse_data {
        /* Configuration variable name */
        char *name;
 
-       /* Parser function for this variable */
+       /* Parser function for this variable. The parser functions return 0 or 1
+        * to indicate success. Value 0 indicates that the parameter value may
+        * have changed while value 1 means that the value did not change.
+        * Error cases (failure to parse the string) are indicated by returning
+        * -1. */
        int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
                      int line, const char *value);
 
@@ -59,7 +63,7 @@ static int wpa_config_parse_str(const struct parse_data *data,
                                struct wpa_ssid *ssid,
                                int line, const char *value)
 {
-       size_t res_len, *dst_len;
+       size_t res_len, *dst_len, prev_len;
        char **dst, *tmp;
 
        if (os_strcmp(value, "NULL") == 0) {
@@ -105,6 +109,21 @@ static int wpa_config_parse_str(const struct parse_data *data,
 set:
        dst = (char **) (((u8 *) ssid) + (long) data->param1);
        dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+
+       if (data->param2)
+               prev_len = *dst_len;
+       else if (*dst)
+               prev_len = os_strlen(*dst);
+       else
+               prev_len = 0;
+       if ((*dst == NULL && tmp == NULL) ||
+           (*dst && tmp && prev_len == res_len &&
+            os_memcmp(*dst, tmp, res_len) == 0)) {
+               /* No change to the previously configured value */
+               os_free(tmp);
+               return 1;
+       }
+
        os_free(*dst);
        *dst = tmp;
        if (data->param2)
@@ -190,6 +209,9 @@ static int wpa_config_parse_int(const struct parse_data *data,
                           line, value);
                return -1;
        }
+
+       if (*dst == val)
+               return 1;
        *dst = val;
        wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
 
@@ -456,9 +478,17 @@ static int wpa_config_parse_psk(const struct parse_data *data,
                }
                wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
                                      (u8 *) value, len);
+               if (has_ctrl_char((u8 *) value, len)) {
+                       wpa_printf(MSG_ERROR,
+                                  "Line %d: Invalid passphrase character",
+                                  line);
+                       return -1;
+               }
                if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
-                   os_memcmp(ssid->passphrase, value, len) == 0)
-                       return 0;
+                   os_memcmp(ssid->passphrase, value, len) == 0) {
+                       /* No change to the previously configured value */
+                       return 1;
+               }
                ssid->psk_set = 0;
                str_clear_free(ssid->passphrase);
                ssid->passphrase = dup_binstr(value, len);
@@ -569,6 +599,8 @@ static int wpa_config_parse_proto(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->proto == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
        ssid->proto = val;
        return errors ? -1 : 0;
@@ -705,6 +737,8 @@ static int wpa_config_parse_key_mgmt(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->key_mgmt == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
        ssid->key_mgmt = val;
        return errors ? -1 : 0;
@@ -899,6 +933,9 @@ static char * wpa_config_write_key_mgmt(const struct parse_data *data,
 
 static int wpa_config_parse_cipher(int line, const char *value)
 {
+#ifdef CONFIG_NO_WPA
+       return -1;
+#else /* CONFIG_NO_WPA */
        int val = wpa_parse_cipher(value);
        if (val < 0) {
                wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
@@ -911,12 +948,16 @@ static int wpa_config_parse_cipher(int line, const char *value)
                return -1;
        }
        return val;
+#endif /* CONFIG_NO_WPA */
 }
 
 
 #ifndef NO_CONFIG_WRITE
 static char * wpa_config_write_cipher(int cipher)
 {
+#ifdef CONFIG_NO_WPA
+       return NULL;
+#else /* CONFIG_NO_WPA */
        char *buf = os_zalloc(50);
        if (buf == NULL)
                return NULL;
@@ -927,6 +968,7 @@ static char * wpa_config_write_cipher(int cipher)
        }
 
        return buf;
+#endif /* CONFIG_NO_WPA */
 }
 #endif /* NO_CONFIG_WRITE */
 
@@ -945,6 +987,8 @@ static int wpa_config_parse_pairwise(const struct parse_data *data,
                return -1;
        }
 
+       if (ssid->pairwise_cipher == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
        ssid->pairwise_cipher = val;
        return 0;
@@ -981,6 +1025,8 @@ static int wpa_config_parse_group(const struct parse_data *data,
                return -1;
        }
 
+       if (ssid->group_cipher == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
        ssid->group_cipher = val;
        return 0;
@@ -1042,6 +1088,8 @@ static int wpa_config_parse_auth_alg(const struct parse_data *data,
                errors++;
        }
 
+       if (!errors && ssid->auth_alg == val)
+               return 1;
        wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
        ssid->auth_alg = val;
        return errors ? -1 : 0;
@@ -1296,6 +1344,32 @@ static int wpa_config_parse_eap(const struct parse_data *data,
        methods[num_methods].method = EAP_TYPE_NONE;
        num_methods++;
 
+       if (!errors && ssid->eap.eap_methods) {
+               struct eap_method_type *prev_m;
+               size_t i, j, prev_methods, match = 0;
+
+               prev_m = ssid->eap.eap_methods;
+               for (i = 0; prev_m[i].vendor != EAP_VENDOR_IETF ||
+                            prev_m[i].method != EAP_TYPE_NONE; i++) {
+                       /* Count the methods */
+               }
+               prev_methods = i + 1;
+
+               for (i = 0; prev_methods == num_methods && i < prev_methods;
+                    i++) {
+                       for (j = 0; j < num_methods; j++) {
+                               if (prev_m[i].vendor == methods[j].vendor &&
+                                   prev_m[i].method == methods[j].method) {
+                                       match++;
+                                       break;
+                               }
+                       }
+               }
+               if (match == num_methods) {
+                       os_free(methods);
+                       return 1;
+               }
+       }
        wpa_hexdump(MSG_MSGDUMP, "eap methods",
                    (u8 *) methods, num_methods * sizeof(*methods));
        os_free(ssid->eap.eap_methods);
@@ -1348,6 +1422,8 @@ static int wpa_config_parse_password(const struct parse_data *data,
        u8 *hash;
 
        if (os_strcmp(value, "NULL") == 0) {
+               if (!ssid->eap.password)
+                       return 1; /* Already unset */
                wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
                bin_clear_free(ssid->eap.password, ssid->eap.password_len);
                ssid->eap.password = NULL;
@@ -1411,6 +1487,12 @@ static int wpa_config_parse_password(const struct parse_data *data,
 
        wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
 
+       if (ssid->eap.password && ssid->eap.password_len == 16 &&
+           os_memcmp(ssid->eap.password, hash, 16) == 0 &&
+           (ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+               bin_clear_free(hash, 16);
+               return 1;
+       }
        bin_clear_free(ssid->eap.password, ssid->eap.password_len);
        ssid->eap.password = hash;
        ssid->eap.password_len = 16;
@@ -1837,6 +1919,8 @@ static const struct parse_data ssid_fields[] = {
        { FUNC(auth_alg) },
        { FUNC(scan_freq) },
        { FUNC(freq_list) },
+       { INT_RANGE(max_oper_chwidth, VHT_CHANWIDTH_USE_HT,
+                   VHT_CHANWIDTH_80P80MHZ) },
 #ifdef IEEE8021X_EAPOL
        { FUNC(eap) },
        { STR_LENe(identity) },
@@ -1910,6 +1994,9 @@ static const struct parse_data ssid_fields[] = {
        { INT_RANGE(mixed_cell, 0, 1) },
        { INT_RANGE(frequency, 0, 65000) },
        { INT_RANGE(fixed_freq, 0, 1) },
+#ifdef CONFIG_ACS
+       { INT_RANGE(acs, 0, 1) },
+#endif /* CONFIG_ACS */
 #ifdef CONFIG_MESH
        { FUNC(mesh_basic_rates) },
        { INT(dot11MeshMaxRetries) },
@@ -1918,6 +2005,7 @@ static const struct parse_data ssid_fields[] = {
        { INT(dot11MeshHoldingTimeout) },
 #endif /* CONFIG_MESH */
        { INT(wpa_ptk_rekey) },
+       { INT(group_rekey) },
        { STR(bgscan) },
        { INT_RANGE(ignore_broadcast_ssid, 0, 2) },
 #ifdef CONFIG_P2P
@@ -1967,6 +2055,8 @@ static const struct parse_data ssid_fields[] = {
        { INT(update_identifier) },
 #endif /* CONFIG_HS20 */
        { INT_RANGE(mac_addr, 0, 2) },
+       { INT_RANGE(pbss, 0, 2) },
+       { INT_RANGE(wps_disabled, 0, 1) },
 };
 
 #undef OFFSET
@@ -2271,6 +2361,11 @@ void wpa_config_free(struct wpa_config *config)
        os_free(config->bgscan);
        os_free(config->wowlan_triggers);
        os_free(config->fst_group_id);
+       os_free(config->sched_scan_plans);
+#ifdef CONFIG_MBO
+       os_free(config->non_pref_chan);
+#endif /* CONFIG_MBO */
+
        os_free(config);
 }
 
@@ -2453,7 +2548,8 @@ void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
  * @var: Variable name, e.g., "ssid"
  * @value: Variable value
  * @line: Line number in configuration file or 0 if not used
- * Returns: 0 on success, -1 on failure
+ * Returns: 0 on success with possible change in the value, 1 on success with
+ * no change to previously configured value, or -1 on failure
  *
  * This function can be used to set network configuration variables based on
  * both the configuration file and management interface input. The value
@@ -2474,7 +2570,8 @@ int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
                if (os_strcmp(var, field->name) != 0)
                        continue;
 
-               if (field->parser(field, ssid, line, value)) {
+               ret = field->parser(field, ssid, line, value);
+               if (ret < 0) {
                        if (line) {
                                wpa_printf(MSG_ERROR, "Line %d: failed to "
                                           "parse %s '%s'.", line, var, value);
@@ -2573,9 +2670,8 @@ char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
        return props;
 
 err:
-       value = *props;
-       while (value)
-               os_free(value++);
+       for (i = 0; props[i]; i++)
+               os_free(props[i]);
        os_free(props);
        return NULL;
 #endif /* NO_CONFIG_WRITE */
@@ -2604,8 +2700,19 @@ char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
 
        for (i = 0; i < NUM_SSID_FIELDS; i++) {
                const struct parse_data *field = &ssid_fields[i];
-               if (os_strcmp(var, field->name) == 0)
-                       return field->writer(field, ssid);
+               if (os_strcmp(var, field->name) == 0) {
+                       char *ret = field->writer(field, ssid);
+
+                       if (ret && has_newline(ret)) {
+                               wpa_printf(MSG_ERROR,
+                                          "Found newline in value for %s; not returning it",
+                                          var);
+                               os_free(ret);
+                               ret = NULL;
+                       }
+
+                       return ret;
+               }
        }
 
        return NULL;
@@ -2790,6 +2897,8 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
 
        if (os_strcmp(var, "password") == 0 &&
            os_strncmp(value, "ext:", 4) == 0) {
+               if (has_newline(value))
+                       return -1;
                str_clear_free(cred->password);
                cred->password = os_strdup(value);
                cred->ext_password = 1;
@@ -2840,9 +2949,14 @@ int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
        }
 
        val = wpa_config_parse_string(value, &len);
-       if (val == NULL) {
+       if (val == NULL ||
+           (os_strcmp(var, "excluded_ssid") != 0 &&
+            os_strcmp(var, "roaming_consortium") != 0 &&
+            os_strcmp(var, "required_roaming_consortium") != 0 &&
+            has_newline(val))) {
                wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
                           "value '%s'.", line, var, value);
+               os_free(val);
                return -1;
        }
 
@@ -3540,6 +3654,11 @@ struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
        config->rand_addr_lifetime = DEFAULT_RAND_ADDR_LIFETIME;
        config->key_mgmt_offload = DEFAULT_KEY_MGMT_OFFLOAD;
        config->cert_in_cb = DEFAULT_CERT_IN_CB;
+       config->wpa_rsc_relaxation = DEFAULT_WPA_RSC_RELAXATION;
+
+#ifdef CONFIG_MBO
+       config->mbo_cell_capa = DEFAULT_MBO_CELL_CAPA;
+#endif /* CONFIG_MBO */
 
        if (ctrl_interface)
                config->ctrl_interface = os_strdup(ctrl_interface);
@@ -3646,6 +3765,12 @@ static int wpa_global_config_parse_str(const struct global_parse_data *data,
                return -1;
        }
 
+       if (has_newline(pos)) {
+               wpa_printf(MSG_ERROR, "Line %d: invalid %s value with newline",
+                          line, data->name);
+               return -1;
+       }
+
        tmp = os_strdup(pos);
        if (tmp == NULL)
                return -1;
@@ -3684,22 +3809,12 @@ static int wpa_global_config_parse_bin(const struct global_parse_data *data,
                                       struct wpa_config *config, int line,
                                       const char *pos)
 {
-       size_t len;
        struct wpabuf **dst, *tmp;
 
-       len = os_strlen(pos);
-       if (len & 0x01)
-               return -1;
-
-       tmp = wpabuf_alloc(len / 2);
-       if (tmp == NULL)
+       tmp = wpabuf_parse_bin(pos);
+       if (!tmp)
                return -1;
 
-       if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
-               wpabuf_free(tmp);
-               return -1;
-       }
-
        dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
        wpabuf_free(*dst);
        *dst = tmp;
@@ -4246,6 +4361,16 @@ static const struct global_parse_data global_fields[] = {
        { INT_RANGE(fst_priority, 1, FST_MAX_PRIO_VALUE), 0 },
        { INT_RANGE(fst_llt, 1, FST_MAX_LLT_MS), 0 },
 #endif /* CONFIG_FST */
+       { INT_RANGE(wpa_rsc_relaxation, 0, 1), 0 },
+       { STR(sched_scan_plans), CFG_CHANGED_SCHED_SCAN_PLANS },
+#ifdef CONFIG_MBO
+       { STR(non_pref_chan), 0 },
+       { INT_RANGE(mbo_cell_capa, MBO_CELL_CAPA_AVAILABLE,
+                   MBO_CELL_CAPA_NOT_SUPPORTED), 0 },
+#endif /*CONFIG_MBO */
+       { INT(gas_address3), 0 },
+       { INT_RANGE(ftm_responder, 0, 1), 0 },
+       { INT_RANGE(ftm_initiator, 0, 1), 0 },
 };
 
 #undef FUNC
@@ -4304,6 +4429,23 @@ int wpa_config_get_value(const char *name, struct wpa_config *config,
 }
 
 
+int wpa_config_get_num_global_field_names(void)
+{
+       return NUM_GLOBAL_FIELDS;
+}
+
+
+const char * wpa_config_get_global_field_name(unsigned int i, int *no_var)
+{
+       if (i >= NUM_GLOBAL_FIELDS)
+               return NULL;
+
+       if (no_var)
+               *no_var = !global_fields[i].param1;
+       return global_fields[i].name;
+}
+
+
 int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
 {
        size_t i;