2 * WPA Supplicant / Configuration file parser
3 * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
12 * See README and COPYING for more details.
23 #include "wpa_supplicant.h"
31 int (*parser)(struct parse_data *data, int line, const char *value);
32 void *param1, *param2, *param3, *param4;
33 struct wpa_ssid *ssid;
38 static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
40 char *pos, *end, *sstart;
42 while (fgets(s, size, stream)) {
47 while (*pos == ' ' || *pos == '\t' || *pos == '\r')
49 if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
53 /* Remove # comments unless they are within a double quoted
54 * string. Remove trailing white space. */
55 sstart = strchr(pos, '"');
57 sstart = strchr(sstart + 1, '"');
60 end = strchr(sstart, '#');
64 end = pos + strlen(pos) - 1;
66 (*end == '\n' || *end == ' ' || *end == '\t' ||
80 static char * wpa_config_parse_string(const char *value, size_t *len)
85 pos = strchr(value, '"');
86 if (pos == NULL || pos[1] != '\0')
93 int hlen = strlen(value);
100 if (hexstr2bin(value, str, *len)) {
109 static int wpa_config_parse_str(struct parse_data *data,
110 int line, const char *value)
112 size_t res_len, *dst_len;
115 dst = (char **) (((u8 *) data->ssid) + (long) data->param1);
116 dst_len = (size_t *) (((u8 *) data->ssid) + (long) data->param2);
119 *dst = wpa_config_parse_string(value, &res_len);
121 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
122 line, data->name, value);
128 if (data->key_data) {
129 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
130 (u8 *) *dst, res_len);
132 wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
133 (u8 *) *dst, res_len);
136 if (data->param3 && res_len < (size_t) data->param3) {
137 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
138 "min_len=%ld)", line, data->name,
139 (unsigned long) res_len, (long) data->param3);
145 if (data->param4 && res_len > (size_t) data->param4) {
146 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
147 "max_len=%ld)", line, data->name,
148 (unsigned long) res_len, (long) data->param4);
158 static int wpa_config_parse_int(struct parse_data *data,
159 int line, const char *value)
163 dst = (int *) (((u8 *) data->ssid) + (long) data->param1);
165 wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
167 if (data->param3 && *dst < (long) data->param3) {
168 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
169 "min_value=%ld)", line, data->name, *dst,
170 (long) data->param3);
171 *dst = (long) data->param3;
175 if (data->param4 && *dst > (long) data->param4) {
176 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
177 "max_value=%ld)", line, data->name, *dst,
178 (long) data->param4);
179 *dst = (long) data->param4;
187 static int wpa_config_parse_bssid(struct parse_data *data, int line,
190 if (hwaddr_aton(value, data->ssid->bssid)) {
191 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
195 data->ssid->bssid_set = 1;
196 wpa_hexdump(MSG_MSGDUMP, "BSSID", data->ssid->bssid, ETH_ALEN);
201 static int wpa_config_parse_psk(struct parse_data *data, int line,
209 pos = strrchr(value, '"');
213 if (len < 8 || len > 63) {
214 wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
215 "length %d (expected: 8..63) '%s'.",
219 wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
221 data->ssid->passphrase = strdup(value);
222 return data->ssid->passphrase == NULL ? -1 : 0;
225 if (hexstr2bin(value, data->ssid->psk, PMK_LEN) ||
226 value[PMK_LEN * 2] != '\0') {
227 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
231 data->ssid->psk_set = 1;
232 wpa_hexdump_key(MSG_MSGDUMP, "PSK", data->ssid->psk, PMK_LEN);
237 static int wpa_config_parse_proto(struct parse_data *data, int line,
240 int val = 0, last, errors = 0;
241 char *start, *end, *buf;
248 while (*start != '\0') {
249 while (*start == ' ' || *start == '\t')
254 while (*end != ' ' && *end != '\t' && *end != '\0')
258 if (strcmp(start, "WPA") == 0)
259 val |= WPA_PROTO_WPA;
260 else if (strcmp(start, "RSN") == 0 ||
261 strcmp(start, "WPA2") == 0)
262 val |= WPA_PROTO_RSN;
264 wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
276 wpa_printf(MSG_ERROR,
277 "Line %d: no proto values configured.", line);
281 wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
282 data->ssid->proto = val;
283 return errors ? -1 : 0;
287 static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
290 int val = 0, last, errors = 0;
291 char *start, *end, *buf;
298 while (*start != '\0') {
299 while (*start == ' ' || *start == '\t')
304 while (*end != ' ' && *end != '\t' && *end != '\0')
308 if (strcmp(start, "WPA-PSK") == 0)
309 val |= WPA_KEY_MGMT_PSK;
310 else if (strcmp(start, "WPA-EAP") == 0)
311 val |= WPA_KEY_MGMT_IEEE8021X;
312 else if (strcmp(start, "IEEE8021X") == 0)
313 val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
314 else if (strcmp(start, "NONE") == 0)
315 val |= WPA_KEY_MGMT_NONE;
316 else if (strcmp(start, "WPA-NONE") == 0)
317 val |= WPA_KEY_MGMT_WPA_NONE;
319 wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
331 wpa_printf(MSG_ERROR,
332 "Line %d: no key_mgmt values configured.", line);
336 wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
337 data->ssid->key_mgmt = val;
338 return errors ? -1 : 0;
342 static int wpa_config_parse_cipher(int line, const char *value)
345 char *start, *end, *buf;
352 while (*start != '\0') {
353 while (*start == ' ' || *start == '\t')
358 while (*end != ' ' && *end != '\t' && *end != '\0')
362 if (strcmp(start, "CCMP") == 0)
363 val |= WPA_CIPHER_CCMP;
364 else if (strcmp(start, "TKIP") == 0)
365 val |= WPA_CIPHER_TKIP;
366 else if (strcmp(start, "WEP104") == 0)
367 val |= WPA_CIPHER_WEP104;
368 else if (strcmp(start, "WEP40") == 0)
369 val |= WPA_CIPHER_WEP40;
370 else if (strcmp(start, "NONE") == 0)
371 val |= WPA_CIPHER_NONE;
373 wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
386 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
394 static int wpa_config_parse_pairwise(struct parse_data *data, int line,
398 val = wpa_config_parse_cipher(line, value);
401 if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
402 wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
403 "(0x%x).", line, val);
407 wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
408 data->ssid->pairwise_cipher = val;
413 static int wpa_config_parse_group(struct parse_data *data, int line,
417 val = wpa_config_parse_cipher(line, value);
420 if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
422 wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
423 "(0x%x).", line, val);
427 wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
428 data->ssid->group_cipher = val;
433 static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
436 int val = 0, last, errors = 0;
437 char *start, *end, *buf;
444 while (*start != '\0') {
445 while (*start == ' ' || *start == '\t')
450 while (*end != ' ' && *end != '\t' && *end != '\0')
454 if (strcmp(start, "OPEN") == 0)
455 val |= WPA_AUTH_ALG_OPEN;
456 else if (strcmp(start, "SHARED") == 0)
457 val |= WPA_AUTH_ALG_SHARED;
458 else if (strcmp(start, "LEAP") == 0)
459 val |= WPA_AUTH_ALG_LEAP;
461 wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
473 wpa_printf(MSG_ERROR,
474 "Line %d: no auth_alg values configured.", line);
478 wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
479 data->ssid->auth_alg = val;
480 return errors ? -1 : 0;
484 static int wpa_config_parse_eap(struct parse_data *data, int line,
487 int last, errors = 0;
488 char *start, *end, *buf;
489 u8 *methods = NULL, *tmp;
490 size_t num_methods = 0;
497 while (*start != '\0') {
498 while (*start == ' ' || *start == '\t')
503 while (*end != ' ' && *end != '\t' && *end != '\0')
508 methods = realloc(methods, num_methods + 1);
509 if (methods == NULL) {
513 methods[num_methods] = eap_get_type(start);
514 if (methods[num_methods] == EAP_TYPE_NONE) {
515 wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
516 "'%s'", line, start);
517 wpa_printf(MSG_ERROR, "You may need to add support for"
518 " this EAP method during wpa_supplicant\n"
519 "build time configuration.\n"
520 "See README for more information.");
522 } else if (methods[num_methods] == EAP_TYPE_LEAP)
525 data->ssid->non_leap++;
534 methods = realloc(methods, num_methods + 1);
535 if (methods == NULL) {
539 methods[num_methods] = EAP_TYPE_NONE;
542 wpa_hexdump(MSG_MSGDUMP, "eap methods", methods, num_methods);
543 data->ssid->eap_methods = methods;
544 return errors ? -1 : 0;
548 static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
549 const char *value, int idx)
551 char *buf, title[20];
553 buf = wpa_config_parse_string(value, len);
555 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
559 if (*len > MAX_WEP_KEY_LEN) {
560 wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
565 memcpy(key, buf, *len);
567 snprintf(title, sizeof(title), "wep_key%d", idx);
568 wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
573 static int wpa_config_parse_wep_key0(struct parse_data *data, int line,
576 return wpa_config_parse_wep_key(data->ssid->wep_key[0],
577 &data->ssid->wep_key_len[0], line,
582 static int wpa_config_parse_wep_key1(struct parse_data *data, int line,
585 return wpa_config_parse_wep_key(data->ssid->wep_key[1],
586 &data->ssid->wep_key_len[1], line,
591 static int wpa_config_parse_wep_key2(struct parse_data *data, int line,
594 return wpa_config_parse_wep_key(data->ssid->wep_key[2],
595 &data->ssid->wep_key_len[2], line,
600 static int wpa_config_parse_wep_key3(struct parse_data *data, int line,
603 return wpa_config_parse_wep_key(data->ssid->wep_key[3],
604 &data->ssid->wep_key_len[3], line,
609 #define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
610 #define STR(f) .name = #f, .parser = wpa_config_parse_str, .param1 = OFFSET(f)
611 #define STR_LEN(f) STR(f), .param2 = OFFSET(f ## _len)
612 #define STR_RANGE(f, min, max) STR_LEN(f), .param3 = (void *) (min), \
613 .param4 = (void *) (max)
614 #define INT(f) .name = #f, .parser = wpa_config_parse_int, \
615 .param1 = OFFSET(f), .param2 = (void *) 0
616 #define INT_RANGE(f, min, max) INT(f), .param3 = (void *) (min), \
617 .param4 = (void *) (max)
618 #define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f
620 static struct parse_data ssid_fields[] = {
621 { STR_RANGE(ssid, 0, MAX_SSID_LEN) },
622 { INT_RANGE(scan_ssid, 0, 1) },
624 { FUNC(psk), .key_data = 1 },
631 { STR_LEN(identity) },
632 { STR_LEN(anonymous_identity) },
633 { STR_RANGE(eappsk, EAP_PSK_LEN, EAP_PSK_LEN), .key_data = 1 },
635 { STR_LEN(server_nai) },
636 { STR_LEN(password), .key_data = 1 },
638 { STR(client_cert) },
639 { STR(private_key) },
640 { STR(private_key_passwd), .key_data = 1 },
642 { STR(subject_match) },
644 { STR(client_cert2) },
645 { STR(private_key2) },
646 { STR(private_key2_passwd), .key_data = 1 },
648 { STR(subject_match2) },
652 { STR(pin), .key_data = 1 },
653 { INT(eapol_flags) },
654 { FUNC(wep_key0), .key_data = 1 },
655 { FUNC(wep_key1), .key_data = 1 },
656 { FUNC(wep_key2), .key_data = 1 },
657 { FUNC(wep_key3), .key_data = 1 },
658 { INT(wep_tx_keyidx) },
660 { INT(eap_workaround) },
662 { INT_RANGE(mode, 0, 1) },
672 #define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
675 static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
677 struct wpa_ssid *ssid;
678 int errors = 0, i, end = 0;
679 char buf[256], *pos, *pos2;
681 wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
683 ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
686 memset(ssid, 0, sizeof(*ssid));
689 ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
690 ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
691 ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
692 WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
693 ssid->key_mgmt = WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X;
694 ssid->eapol_flags = EAPOL_FLAG_REQUIRE_KEY_UNICAST |
695 EAPOL_FLAG_REQUIRE_KEY_BROADCAST;
696 ssid->eap_workaround = (unsigned int) -1;
698 while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
699 if (strcmp(pos, "}") == 0) {
704 pos2 = strchr(pos, '=');
706 wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
707 "'%s'.", *line, pos);
714 if (strchr(pos2 + 1, '"') == NULL) {
715 wpa_printf(MSG_ERROR, "Line %d: invalid "
716 "quotation '%s'.", *line, pos2);
722 for (i = 0; i < NUM_SSID_FIELDS; i++) {
723 struct parse_data *field = &ssid_fields[i];
724 if (strcmp(pos, field->name) != 0)
728 if (field->parser(field, *line, pos2)) {
729 wpa_printf(MSG_ERROR, "Line %d: failed to "
730 "parse %s '%s'.", *line, pos, pos2);
735 if (i == NUM_SSID_FIELDS) {
736 wpa_printf(MSG_ERROR, "Line %d: unknown network field "
737 "'%s'.", *line, pos);
743 wpa_printf(MSG_ERROR, "Line %d: network block was not "
744 "terminated properly.", *line);
748 if (ssid->passphrase) {
750 wpa_printf(MSG_ERROR, "Line %d: both PSK and "
751 "passphrase configured.", *line);
754 pbkdf2_sha1(ssid->passphrase,
755 (char *) ssid->ssid, ssid->ssid_len, 4096,
757 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
762 if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
763 wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
764 "management, but no PSK configured.", *line);
768 if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
769 !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
770 /* Group cipher cannot be stronger than the pairwise cipher. */
771 wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
772 " list since it was not allowed for pairwise "
774 ssid->group_cipher &= ~WPA_CIPHER_CCMP;
786 static int wpa_config_add_prio_network(struct wpa_config *config,
787 struct wpa_ssid *ssid)
790 struct wpa_ssid *prev, **nlist;
792 for (prio = 0; prio < config->num_prio; prio++) {
793 prev = config->pssid[prio];
794 if (prev->priority == ssid->priority) {
802 /* First network for this priority - add new priority list */
803 nlist = realloc(config->pssid,
804 (config->num_prio + 1) * sizeof(struct wpa_ssid *));
808 for (prio = 0; prio < config->num_prio; prio++) {
809 if (nlist[prio]->priority < ssid->priority)
813 memmove(&nlist[prio + 1], &nlist[prio],
814 (config->num_prio - prio) * sizeof(struct wpa_ssid *));
818 config->pssid = nlist;
824 struct wpa_config * wpa_config_read(const char *config_file)
828 int errors = 0, line = 0;
829 struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
830 struct wpa_config *config;
833 config = malloc(sizeof(*config));
836 memset(config, 0, sizeof(*config));
837 config->eapol_version = 1;
839 config->fast_reauth = 1;
840 wpa_printf(MSG_DEBUG, "Reading configuration file '%s'",
842 f = fopen(config_file, "r");
848 while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
849 if (strcmp(pos, "network={") == 0) {
850 ssid = wpa_config_read_network(f, &line, id++);
852 wpa_printf(MSG_ERROR, "Line %d: failed to "
853 "parse network block.", line);
863 if (wpa_config_add_prio_network(config, ssid)) {
864 wpa_printf(MSG_ERROR, "Line %d: failed to add "
865 "network block to priority list.",
870 #ifdef CONFIG_CTRL_IFACE
871 } else if (strncmp(pos, "ctrl_interface=", 15) == 0) {
872 free(config->ctrl_interface);
873 config->ctrl_interface = strdup(pos + 15);
874 wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
875 config->ctrl_interface);
876 #ifndef CONFIG_CTRL_IFACE_UDP
877 } else if (strncmp(pos, "ctrl_interface_group=", 21) == 0) {
880 const char *group = pos + 21;
882 grp = getgrnam(group);
884 config->ctrl_interface_gid = grp->gr_gid;
885 config->ctrl_interface_gid_set = 1;
886 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
887 " (from group name '%s')",
888 (int) config->ctrl_interface_gid,
893 /* Group name not found - try to parse this as gid */
894 config->ctrl_interface_gid = strtol(group, &endp, 10);
895 if (*group == '\0' || *endp != '\0') {
896 wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
897 "'%s'", line, group);
901 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
902 (int) config->ctrl_interface_gid);
903 #endif /* CONFIG_CTRL_IFACE_UDP */
904 #endif /* CONFIG_CTRL_IFACE */
905 } else if (strncmp(pos, "eapol_version=", 14) == 0) {
906 config->eapol_version = atoi(pos + 14);
907 if (config->eapol_version < 1 ||
908 config->eapol_version > 2) {
909 wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
910 "version (%d): '%s'.",
911 line, config->eapol_version, pos);
915 wpa_printf(MSG_DEBUG, "eapol_version=%d",
916 config->eapol_version);
917 } else if (strncmp(pos, "ap_scan=", 8) == 0) {
918 config->ap_scan = atoi(pos + 8);
919 wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
920 } else if (strncmp(pos, "fast_reauth=", 12) == 0) {
921 config->fast_reauth = atoi(pos + 12);
922 wpa_printf(MSG_DEBUG, "fast_reauth=%d",
923 config->fast_reauth);
925 wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
926 "line '%s'.", line, pos);
935 for (prio = 0; prio < config->num_prio; prio++) {
936 ssid = config->pssid[prio];
937 wpa_printf(MSG_DEBUG, "Priority group %d",
940 wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
942 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
947 wpa_config_free(config);
956 void wpa_config_free(struct wpa_config *config)
958 struct wpa_ssid *ssid, *prev = NULL;
964 free(prev->passphrase);
965 free(prev->eap_methods);
966 free(prev->identity);
967 free(prev->anonymous_identity);
970 free(prev->server_nai);
971 free(prev->password);
973 free(prev->client_cert);
974 free(prev->private_key);
975 free(prev->private_key_passwd);
977 free(prev->subject_match);
978 free(prev->ca_cert2);
979 free(prev->client_cert2);
980 free(prev->private_key2);
981 free(prev->private_key2_passwd);
982 free(prev->dh_file2);
983 free(prev->subject_match2);
989 free(prev->pending_req_otp);
990 free(prev->pac_file);
993 free(config->ctrl_interface);
999 int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
1003 if (ssid == NULL || ssid->eap_methods == NULL)
1006 pos = ssid->eap_methods;
1007 while (*pos != EAP_TYPE_NONE) {
1016 const char * wpa_cipher_txt(int cipher)
1019 case WPA_CIPHER_NONE:
1021 case WPA_CIPHER_WEP40:
1023 case WPA_CIPHER_WEP104:
1025 case WPA_CIPHER_TKIP:
1027 case WPA_CIPHER_CCMP:
1035 const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
1038 case WPA_KEY_MGMT_IEEE8021X:
1039 return proto == WPA_PROTO_RSN ?
1040 "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
1041 case WPA_KEY_MGMT_PSK:
1042 return proto == WPA_PROTO_RSN ?
1043 "WPA2-PSK" : "WPA-PSK";
1044 case WPA_KEY_MGMT_NONE:
1046 case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
1047 return "IEEE 802.1X (no WPA)";