summaryrefslogtreecommitdiffstats
path: root/contrib/wpa_supplicant/config.c
diff options
context:
space:
mode:
authorsam <sam@FreeBSD.org>2005-06-05 20:52:14 +0000
committersam <sam@FreeBSD.org>2005-06-05 20:52:14 +0000
commit2b0ba7bae5b60321ee7843871a2cf15ad6b3f65b (patch)
tree98be326632e2ea3857ee0d9f831c91ea0823bb0d /contrib/wpa_supplicant/config.c
downloadFreeBSD-src-2b0ba7bae5b60321ee7843871a2cf15ad6b3f65b.zip
FreeBSD-src-2b0ba7bae5b60321ee7843871a2cf15ad6b3f65b.tar.gz
Stripped down import of wpa_supplicant v0.3.8
Diffstat (limited to 'contrib/wpa_supplicant/config.c')
-rw-r--r--contrib/wpa_supplicant/config.c1051
1 files changed, 1051 insertions, 0 deletions
diff --git a/contrib/wpa_supplicant/config.c b/contrib/wpa_supplicant/config.c
new file mode 100644
index 0000000..241c755
--- /dev/null
+++ b/contrib/wpa_supplicant/config.c
@@ -0,0 +1,1051 @@
+/*
+ * WPA Supplicant / Configuration file parser
+ * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "common.h"
+#include "wpa.h"
+#include "config.h"
+#include "sha1.h"
+#include "wpa_supplicant.h"
+#include "eapol_sm.h"
+#include "eap.h"
+#include "config.h"
+
+
+struct parse_data {
+ char *name;
+ int (*parser)(struct parse_data *data, int line, const char *value);
+ void *param1, *param2, *param3, *param4;
+ struct wpa_ssid *ssid;
+ int key_data;
+};
+
+
+static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
+{
+ char *pos, *end, *sstart;
+
+ while (fgets(s, size, stream)) {
+ (*line)++;
+ s[size - 1] = '\0';
+ pos = s;
+
+ while (*pos == ' ' || *pos == '\t' || *pos == '\r')
+ pos++;
+ if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
+ *pos == '\r')
+ continue;
+
+ /* Remove # comments unless they are within a double quoted
+ * string. Remove trailing white space. */
+ sstart = strchr(pos, '"');
+ if (sstart)
+ sstart = strchr(sstart + 1, '"');
+ if (!sstart)
+ sstart = pos;
+ end = strchr(sstart, '#');
+ if (end)
+ *end-- = '\0';
+ else
+ end = pos + strlen(pos) - 1;
+ while (end > pos &&
+ (*end == '\n' || *end == ' ' || *end == '\t' ||
+ *end == '\r')) {
+ *end-- = '\0';
+ }
+ if (*pos == '\0')
+ continue;
+
+ return pos;
+ }
+
+ return NULL;
+}
+
+
+static char * wpa_config_parse_string(const char *value, size_t *len)
+{
+ if (*value == '"') {
+ char *pos;
+ value++;
+ pos = strchr(value, '"');
+ if (pos == NULL || pos[1] != '\0')
+ return NULL;
+ *pos = '\0';
+ *len = strlen(value);
+ return strdup(value);
+ } else {
+ u8 *str;
+ int hlen = strlen(value);
+ if (hlen % 1)
+ return NULL;
+ *len = hlen / 2;
+ str = malloc(*len);
+ if (str == NULL)
+ return NULL;
+ if (hexstr2bin(value, str, *len)) {
+ free(str);
+ return NULL;
+ }
+ return (char *) str;
+ }
+}
+
+
+static int wpa_config_parse_str(struct parse_data *data,
+ int line, const char *value)
+{
+ size_t res_len, *dst_len;
+ char **dst;
+
+ dst = (char **) (((u8 *) data->ssid) + (long) data->param1);
+ dst_len = (size_t *) (((u8 *) data->ssid) + (long) data->param2);
+
+ free(*dst);
+ *dst = wpa_config_parse_string(value, &res_len);
+ if (*dst == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
+ line, data->name, value);
+ return -1;
+ }
+ if (data->param2)
+ *dst_len = res_len;
+
+ if (data->key_data) {
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+ (u8 *) *dst, res_len);
+ } else {
+ wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
+ (u8 *) *dst, res_len);
+ }
+
+ if (data->param3 && res_len < (size_t) data->param3) {
+ wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
+ "min_len=%ld)", line, data->name,
+ (unsigned long) res_len, (long) data->param3);
+ free(*dst);
+ *dst = NULL;
+ return -1;
+ }
+
+ if (data->param4 && res_len > (size_t) data->param4) {
+ wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
+ "max_len=%ld)", line, data->name,
+ (unsigned long) res_len, (long) data->param4);
+ free(*dst);
+ *dst = NULL;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_config_parse_int(struct parse_data *data,
+ int line, const char *value)
+{
+ int *dst;
+
+ dst = (int *) (((u8 *) data->ssid) + (long) data->param1);
+ *dst = atoi(value);
+ wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
+
+ if (data->param3 && *dst < (long) data->param3) {
+ wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+ "min_value=%ld)", line, data->name, *dst,
+ (long) data->param3);
+ *dst = (long) data->param3;
+ return -1;
+ }
+
+ if (data->param4 && *dst > (long) data->param4) {
+ wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+ "max_value=%ld)", line, data->name, *dst,
+ (long) data->param4);
+ *dst = (long) data->param4;
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_config_parse_bssid(struct parse_data *data, int line,
+ const char *value)
+{
+ if (hwaddr_aton(value, data->ssid->bssid)) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
+ line, value);
+ return -1;
+ }
+ data->ssid->bssid_set = 1;
+ wpa_hexdump(MSG_MSGDUMP, "BSSID", data->ssid->bssid, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_config_parse_psk(struct parse_data *data, int line,
+ const char *value)
+{
+ if (*value == '"') {
+ char *pos;
+ int len;
+
+ value++;
+ pos = strrchr(value, '"');
+ if (pos)
+ *pos = '\0';
+ len = strlen(value);
+ if (len < 8 || len > 63) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
+ "length %d (expected: 8..63) '%s'.",
+ line, len, value);
+ return -1;
+ }
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
+ (u8 *) value, len);
+ data->ssid->passphrase = strdup(value);
+ return data->ssid->passphrase == NULL ? -1 : 0;
+ }
+
+ if (hexstr2bin(value, data->ssid->psk, PMK_LEN) ||
+ value[PMK_LEN * 2] != '\0') {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
+ line, value);
+ return -1;
+ }
+ data->ssid->psk_set = 1;
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK", data->ssid->psk, PMK_LEN);
+ return 0;
+}
+
+
+static int wpa_config_parse_proto(struct parse_data *data, int line,
+ const char *value)
+{
+ int val = 0, last, errors = 0;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "WPA") == 0)
+ val |= WPA_PROTO_WPA;
+ else if (strcmp(start, "RSN") == 0 ||
+ strcmp(start, "WPA2") == 0)
+ val |= WPA_PROTO_RSN;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
+ line, start);
+ errors++;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: no proto values configured.", line);
+ errors++;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
+ data->ssid->proto = val;
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
+ const char *value)
+{
+ int val = 0, last, errors = 0;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "WPA-PSK") == 0)
+ val |= WPA_KEY_MGMT_PSK;
+ else if (strcmp(start, "WPA-EAP") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X;
+ else if (strcmp(start, "IEEE8021X") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+ else if (strcmp(start, "NONE") == 0)
+ val |= WPA_KEY_MGMT_NONE;
+ else if (strcmp(start, "WPA-NONE") == 0)
+ val |= WPA_KEY_MGMT_WPA_NONE;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
+ line, start);
+ errors++;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: no key_mgmt values configured.", line);
+ errors++;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
+ data->ssid->key_mgmt = val;
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_parse_cipher(int line, const char *value)
+{
+ int val = 0, last;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "CCMP") == 0)
+ val |= WPA_CIPHER_CCMP;
+ else if (strcmp(start, "TKIP") == 0)
+ val |= WPA_CIPHER_TKIP;
+ else if (strcmp(start, "WEP104") == 0)
+ val |= WPA_CIPHER_WEP104;
+ else if (strcmp(start, "WEP40") == 0)
+ val |= WPA_CIPHER_WEP40;
+ else if (strcmp(start, "NONE") == 0)
+ val |= WPA_CIPHER_NONE;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+ line, start);
+ free(buf);
+ return -1;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+ line);
+ return -1;
+ }
+ return val;
+}
+
+
+static int wpa_config_parse_pairwise(struct parse_data *data, int line,
+ const char *value)
+{
+ int val;
+ val = wpa_config_parse_cipher(line, value);
+ if (val == -1)
+ return -1;
+ if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
+ wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
+ "(0x%x).", line, val);
+ return -1;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
+ data->ssid->pairwise_cipher = val;
+ return 0;
+}
+
+
+static int wpa_config_parse_group(struct parse_data *data, int line,
+ const char *value)
+{
+ int val;
+ 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)) {
+ wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
+ "(0x%x).", line, val);
+ return -1;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
+ data->ssid->group_cipher = val;
+ return 0;
+}
+
+
+static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
+ const char *value)
+{
+ int val = 0, last, errors = 0;
+ char *start, *end, *buf;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ if (strcmp(start, "OPEN") == 0)
+ val |= WPA_AUTH_ALG_OPEN;
+ else if (strcmp(start, "SHARED") == 0)
+ val |= WPA_AUTH_ALG_SHARED;
+ else if (strcmp(start, "LEAP") == 0)
+ val |= WPA_AUTH_ALG_LEAP;
+ else {
+ wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
+ line, start);
+ errors++;
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ if (val == 0) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: no auth_alg values configured.", line);
+ errors++;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
+ data->ssid->auth_alg = val;
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_parse_eap(struct parse_data *data, int line,
+ const char *value)
+{
+ int last, errors = 0;
+ char *start, *end, *buf;
+ u8 *methods = NULL, *tmp;
+ size_t num_methods = 0;
+
+ buf = strdup(value);
+ if (buf == NULL)
+ return -1;
+ start = buf;
+
+ while (start != '\0') {
+ while (*start == ' ' || *start == '\t')
+ start++;
+ if (*start == '\0')
+ break;
+ end = start;
+ while (*end != ' ' && *end != '\t' && *end != '\0')
+ end++;
+ last = *end == '\0';
+ *end = '\0';
+ tmp = methods;
+ methods = realloc(methods, num_methods + 1);
+ if (methods == NULL) {
+ free(tmp);
+ return -1;
+ }
+ methods[num_methods] = eap_get_type(start);
+ if (methods[num_methods] == EAP_TYPE_NONE) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
+ "'%s'", line, start);
+ wpa_printf(MSG_ERROR, "You may need to add support for"
+ " this EAP method during wpa_supplicant\n"
+ "build time configuration.\n"
+ "See README for more information.");
+ errors++;
+ } else if (methods[num_methods] == EAP_TYPE_LEAP)
+ data->ssid->leap++;
+ else
+ data->ssid->non_leap++;
+ num_methods++;
+ if (last)
+ break;
+ start = end + 1;
+ }
+ free(buf);
+
+ tmp = methods;
+ methods = realloc(methods, num_methods + 1);
+ if (methods == NULL) {
+ free(tmp);
+ return -1;
+ }
+ methods[num_methods] = EAP_TYPE_NONE;
+ num_methods++;
+
+ wpa_hexdump(MSG_MSGDUMP, "eap methods", methods, num_methods);
+ data->ssid->eap_methods = methods;
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
+ const char *value, int idx)
+{
+ char *buf, title[20];
+
+ buf = wpa_config_parse_string(value, len);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
+ line, idx, value);
+ return -1;
+ }
+ if (*len > MAX_WEP_KEY_LEN) {
+ wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
+ line, idx, value);
+ free(buf);
+ return -1;
+ }
+ memcpy(key, buf, *len);
+ free(buf);
+ snprintf(title, sizeof(title), "wep_key%d", idx);
+ wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
+ return 0;
+}
+
+
+static int wpa_config_parse_wep_key0(struct parse_data *data, int line,
+ const char *value)
+{
+ return wpa_config_parse_wep_key(data->ssid->wep_key[0],
+ &data->ssid->wep_key_len[0], line,
+ value, 0);
+}
+
+
+static int wpa_config_parse_wep_key1(struct parse_data *data, int line,
+ const char *value)
+{
+ return wpa_config_parse_wep_key(data->ssid->wep_key[1],
+ &data->ssid->wep_key_len[1], line,
+ value, 1);
+}
+
+
+static int wpa_config_parse_wep_key2(struct parse_data *data, int line,
+ const char *value)
+{
+ return wpa_config_parse_wep_key(data->ssid->wep_key[2],
+ &data->ssid->wep_key_len[2], line,
+ value, 2);
+}
+
+
+static int wpa_config_parse_wep_key3(struct parse_data *data, int line,
+ const char *value)
+{
+ return wpa_config_parse_wep_key(data->ssid->wep_key[3],
+ &data->ssid->wep_key_len[3], line,
+ value, 3);
+}
+
+
+#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
+#define STR(f) .name = #f, .parser = wpa_config_parse_str, .param1 = OFFSET(f)
+#define STR_LEN(f) STR(f), .param2 = OFFSET(f ## _len)
+#define STR_RANGE(f, min, max) STR_LEN(f), .param3 = (void *) (min), \
+ .param4 = (void *) (max)
+#define INT(f) .name = #f, .parser = wpa_config_parse_int, \
+ .param1 = OFFSET(f), .param2 = (void *) 0
+#define INT_RANGE(f, min, max) INT(f), .param3 = (void *) (min), \
+ .param4 = (void *) (max)
+#define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f
+
+static struct parse_data ssid_fields[] = {
+ { STR_RANGE(ssid, 0, MAX_SSID_LEN) },
+ { INT_RANGE(scan_ssid, 0, 1) },
+ { FUNC(bssid) },
+ { FUNC(psk), .key_data = 1 },
+ { FUNC(proto) },
+ { FUNC(key_mgmt) },
+ { FUNC(pairwise) },
+ { FUNC(group) },
+ { FUNC(auth_alg) },
+ { FUNC(eap) },
+ { STR_LEN(identity) },
+ { STR_LEN(anonymous_identity) },
+ { STR_RANGE(eappsk, EAP_PSK_LEN, EAP_PSK_LEN), .key_data = 1 },
+ { STR_LEN(nai) },
+ { STR_LEN(server_nai) },
+ { STR_LEN(password), .key_data = 1 },
+ { STR(ca_cert) },
+ { STR(client_cert) },
+ { STR(private_key) },
+ { STR(private_key_passwd), .key_data = 1 },
+ { STR(dh_file) },
+ { STR(subject_match) },
+ { STR(ca_cert2) },
+ { STR(client_cert2) },
+ { STR(private_key2) },
+ { STR(private_key2_passwd), .key_data = 1 },
+ { STR(dh_file2) },
+ { STR(subject_match2) },
+ { STR(phase1) },
+ { STR(phase2) },
+ { STR(pcsc) },
+ { STR(pin), .key_data = 1 },
+ { INT(eapol_flags) },
+ { FUNC(wep_key0), .key_data = 1 },
+ { FUNC(wep_key1), .key_data = 1 },
+ { FUNC(wep_key2), .key_data = 1 },
+ { FUNC(wep_key3), .key_data = 1 },
+ { INT(wep_tx_keyidx) },
+ { INT(priority) },
+ { INT(eap_workaround) },
+ { STR(pac_file) },
+ { INT_RANGE(mode, 0, 1) },
+};
+
+#undef OFFSET
+#undef STR
+#undef STR_LEN
+#undef STR_RANGE
+#undef INT
+#undef INT_RANGE
+#undef FUNC
+#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+
+
+static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
+{
+ struct wpa_ssid *ssid;
+ int errors = 0, i, end = 0;
+ char buf[256], *pos, *pos2;
+
+ wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
+ *line);
+ ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
+ if (ssid == NULL)
+ return NULL;
+ memset(ssid, 0, sizeof(*ssid));
+ ssid->id = id;
+
+ ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
+ ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
+ ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
+ WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
+ ssid->key_mgmt = WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X;
+ ssid->eapol_flags = EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+ EAPOL_FLAG_REQUIRE_KEY_BROADCAST;
+ ssid->eap_workaround = (unsigned int) -1;
+
+ while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
+ if (strcmp(pos, "}") == 0) {
+ end = 1;
+ break;
+ }
+
+ pos2 = strchr(pos, '=');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
+ "'%s'.", *line, pos);
+ errors++;
+ continue;
+ }
+
+ *pos2++ = '\0';
+ if (*pos2 == '"') {
+ if (strchr(pos2 + 1, '"') == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid "
+ "quotation '%s'.", *line, pos2);
+ errors++;
+ continue;
+ }
+ }
+
+ for (i = 0; i < NUM_SSID_FIELDS; i++) {
+ struct parse_data *field = &ssid_fields[i];
+ if (strcmp(pos, field->name) != 0)
+ continue;
+
+ field->ssid = ssid;
+ if (field->parser(field, *line, pos2)) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse %s '%s'.", *line, pos, pos2);
+ errors++;
+ }
+ break;
+ }
+ if (i == NUM_SSID_FIELDS) {
+ wpa_printf(MSG_ERROR, "Line %d: unknown network field "
+ "'%s'.", *line, pos);
+ errors++;
+ }
+ }
+
+ if (!end) {
+ wpa_printf(MSG_ERROR, "Line %d: network block was not "
+ "terminated properly.", *line);
+ errors++;
+ }
+
+ if (ssid->passphrase) {
+ if (ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Line %d: both PSK and "
+ "passphrase configured.", *line);
+ errors++;
+ }
+ pbkdf2_sha1(ssid->passphrase,
+ (char *) ssid->ssid, ssid->ssid_len, 4096,
+ ssid->psk, PMK_LEN);
+ wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+ ssid->psk, PMK_LEN);
+ ssid->psk_set = 1;
+ }
+
+ if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
+ "management, but no PSK configured.", *line);
+ errors++;
+ }
+
+ if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
+ /* Group cipher cannot be stronger than the pairwise cipher. */
+ wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
+ " list since it was not allowed for pairwise "
+ "cipher", *line);
+ ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+ }
+
+ if (errors) {
+ free(ssid);
+ ssid = NULL;
+ }
+
+ return ssid;
+}
+
+
+static int wpa_config_add_prio_network(struct wpa_config *config,
+ struct wpa_ssid *ssid)
+{
+ int prio;
+ struct wpa_ssid *prev, **nlist;
+
+ for (prio = 0; prio < config->num_prio; prio++) {
+ prev = config->pssid[prio];
+ if (prev->priority == ssid->priority) {
+ while (prev->pnext)
+ prev = prev->pnext;
+ prev->pnext = ssid;
+ return 0;
+ }
+ }
+
+ /* First network for this priority - add new priority list */
+ nlist = realloc(config->pssid,
+ (config->num_prio + 1) * sizeof(struct wpa_ssid *));
+ if (nlist == NULL)
+ return -1;
+
+ for (prio = 0; prio < config->num_prio; prio++) {
+ if (nlist[prio]->priority < ssid->priority)
+ break;
+ }
+
+ memmove(&nlist[prio + 1], &nlist[prio],
+ (config->num_prio - prio) * sizeof(struct wpa_ssid *));
+
+ nlist[prio] = ssid;
+ config->num_prio++;
+ config->pssid = nlist;
+
+ return 0;
+}
+
+
+struct wpa_config * wpa_config_read(const char *config_file)
+{
+ FILE *f;
+ char buf[256], *pos;
+ int errors = 0, line = 0;
+ struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ struct wpa_config *config;
+ int id = 0, prio;
+
+ config = malloc(sizeof(*config));
+ if (config == NULL)
+ return NULL;
+ memset(config, 0, sizeof(*config));
+ config->eapol_version = 1;
+ config->ap_scan = 1;
+ config->fast_reauth = 1;
+ wpa_printf(MSG_DEBUG, "Reading configuration file '%s'",
+ config_file);
+ f = fopen(config_file, "r");
+ if (f == NULL) {
+ free(config);
+ return NULL;
+ }
+
+ while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
+ if (strcmp(pos, "network={") == 0) {
+ ssid = wpa_config_read_network(f, &line, id++);
+ if (ssid == NULL) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to "
+ "parse network block.", line);
+ errors++;
+ continue;
+ }
+ if (head == NULL) {
+ head = tail = ssid;
+ } else {
+ tail->next = ssid;
+ tail = ssid;
+ }
+ if (wpa_config_add_prio_network(config, ssid)) {
+ wpa_printf(MSG_ERROR, "Line %d: failed to add "
+ "network block to priority list.",
+ line);
+ errors++;
+ continue;
+ }
+#ifdef CONFIG_CTRL_IFACE
+ } else if (strncmp(pos, "ctrl_interface=", 15) == 0) {
+ free(config->ctrl_interface);
+ config->ctrl_interface = strdup(pos + 15);
+ wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
+ config->ctrl_interface);
+#ifndef CONFIG_CTRL_IFACE_UDP
+ } else if (strncmp(pos, "ctrl_interface_group=", 21) == 0) {
+ struct group *grp;
+ char *endp;
+ const char *group = pos + 21;
+
+ grp = getgrnam(group);
+ if (grp) {
+ config->ctrl_interface_gid = grp->gr_gid;
+ config->ctrl_interface_gid_set = 1;
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+ " (from group name '%s')",
+ (int) config->ctrl_interface_gid,
+ group);
+ continue;
+ }
+
+ /* Group name not found - try to parse this as gid */
+ config->ctrl_interface_gid = strtol(group, &endp, 10);
+ if (*group == '\0' || *endp != '\0') {
+ wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
+ "'%s'", line, group);
+ errors++;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+ (int) config->ctrl_interface_gid);
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#endif /* CONFIG_CTRL_IFACE */
+ } else if (strncmp(pos, "eapol_version=", 14) == 0) {
+ config->eapol_version = atoi(pos + 14);
+ if (config->eapol_version < 1 ||
+ config->eapol_version > 2) {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
+ "version (%d): '%s'.",
+ line, config->eapol_version, pos);
+ errors++;
+ continue;
+ }
+ wpa_printf(MSG_DEBUG, "eapol_version=%d",
+ config->eapol_version);
+ } else if (strncmp(pos, "ap_scan=", 8) == 0) {
+ config->ap_scan = atoi(pos + 8);
+ wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
+ } else if (strncmp(pos, "fast_reauth=", 12) == 0) {
+ config->fast_reauth = atoi(pos + 12);
+ wpa_printf(MSG_DEBUG, "fast_reauth=%d",
+ config->fast_reauth);
+ } else {
+ wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
+ "line '%s'.", line, pos);
+ errors++;
+ continue;
+ }
+ }
+
+ fclose(f);
+
+ config->ssid = head;
+ for (prio = 0; prio < config->num_prio; prio++) {
+ ssid = config->pssid[prio];
+ wpa_printf(MSG_DEBUG, "Priority group %d",
+ ssid->priority);
+ while (ssid) {
+ wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
+ ssid->id,
+ wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+ ssid = ssid->pnext;
+ }
+ }
+ if (errors) {
+ wpa_config_free(config);
+ config = NULL;
+ head = NULL;
+ }
+
+ return config;
+}
+
+
+void wpa_config_free(struct wpa_config *config)
+{
+ struct wpa_ssid *ssid, *prev = NULL;
+ ssid = config->ssid;
+ while (ssid) {
+ prev = ssid;
+ ssid = ssid->next;
+ free(prev->ssid);
+ free(prev->passphrase);
+ free(prev->eap_methods);
+ free(prev->identity);
+ free(prev->anonymous_identity);
+ free(prev->eappsk);
+ free(prev->nai);
+ free(prev->server_nai);
+ free(prev->password);
+ free(prev->ca_cert);
+ free(prev->client_cert);
+ free(prev->private_key);
+ free(prev->private_key_passwd);
+ free(prev->dh_file);
+ free(prev->subject_match);
+ free(prev->ca_cert2);
+ free(prev->client_cert2);
+ free(prev->private_key2);
+ free(prev->private_key2_passwd);
+ free(prev->dh_file2);
+ free(prev->subject_match2);
+ free(prev->phase1);
+ free(prev->phase2);
+ free(prev->pcsc);
+ free(prev->pin);
+ free(prev->otp);
+ free(prev->pending_req_otp);
+ free(prev->pac_file);
+ free(prev);
+ }
+ free(config->ctrl_interface);
+ free(config->pssid);
+ free(config);
+}
+
+
+int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
+{
+ u8 *pos;
+
+ if (ssid == NULL || ssid->eap_methods == NULL)
+ return 1;
+
+ pos = ssid->eap_methods;
+ while (*pos != EAP_TYPE_NONE) {
+ if (*pos == method)
+ return 1;
+ pos++;
+ }
+ return 0;
+}
+
+
+const char * wpa_cipher_txt(int cipher)
+{
+ switch (cipher) {
+ case WPA_CIPHER_NONE:
+ return "NONE";
+ case WPA_CIPHER_WEP40:
+ return "WEP-40";
+ case WPA_CIPHER_WEP104:
+ return "WEP-104";
+ case WPA_CIPHER_TKIP:
+ return "TKIP";
+ case WPA_CIPHER_CCMP:
+ return "CCMP";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
+{
+ switch (key_mgmt) {
+ case WPA_KEY_MGMT_IEEE8021X:
+ return proto == WPA_PROTO_RSN ?
+ "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
+ case WPA_KEY_MGMT_PSK:
+ return proto == WPA_PROTO_RSN ?
+ "WPA2-PSK" : "WPA-PSK";
+ case WPA_KEY_MGMT_NONE:
+ return "NONE";
+ case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
+ return "IEEE 802.1X (no WPA)";
+ default:
+ return "UNKNOWN";
+ }
+}
OpenPOWER on IntegriCloud