blob: d36d027ec4261bd4166fbebdafbc9c9b4f9ef477 [file] [log] [blame]
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001/*
2 * WPA Supplicant / Configuration parser and common functions
3 * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
4 *
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08005 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07007 */
8
9#include "includes.h"
10
11#include "common.h"
12#include "utils/uuid.h"
13#include "crypto/sha1.h"
14#include "rsn_supp/wpa.h"
15#include "eap_peer/eap.h"
16#include "config.h"
17
18
19#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
20#define NO_CONFIG_WRITE
21#endif
22
23/*
24 * Structure for network configuration parsing. This data is used to implement
25 * a generic parser for each network block variable. The table of configuration
26 * variables is defined below in this file (ssid_fields[]).
27 */
28struct parse_data {
29 /* Configuration variable name */
30 char *name;
31
32 /* Parser function for this variable */
33 int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
34 int line, const char *value);
35
36#ifndef NO_CONFIG_WRITE
37 /* Writer function (i.e., to get the variable in text format from
38 * internal presentation). */
39 char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
40#endif /* NO_CONFIG_WRITE */
41
42 /* Variable specific parameters for the parser. */
43 void *param1, *param2, *param3, *param4;
44
45 /* 0 = this variable can be included in debug output and ctrl_iface
46 * 1 = this variable contains key/private data and it must not be
47 * included in debug output unless explicitly requested. In
48 * addition, this variable will not be readable through the
49 * ctrl_iface.
50 */
51 int key_data;
52};
53
54
55static char * wpa_config_parse_string(const char *value, size_t *len)
56{
57 if (*value == '"') {
58 const char *pos;
59 char *str;
60 value++;
61 pos = os_strrchr(value, '"');
62 if (pos == NULL || pos[1] != '\0')
63 return NULL;
64 *len = pos - value;
65 str = os_malloc(*len + 1);
66 if (str == NULL)
67 return NULL;
68 os_memcpy(str, value, *len);
69 str[*len] = '\0';
70 return str;
71 } else {
72 u8 *str;
73 size_t tlen, hlen = os_strlen(value);
74 if (hlen & 1)
75 return NULL;
76 tlen = hlen / 2;
77 str = os_malloc(tlen + 1);
78 if (str == NULL)
79 return NULL;
80 if (hexstr2bin(value, str, tlen)) {
81 os_free(str);
82 return NULL;
83 }
84 str[tlen] = '\0';
85 *len = tlen;
86 return (char *) str;
87 }
88}
89
90
91static int wpa_config_parse_str(const struct parse_data *data,
92 struct wpa_ssid *ssid,
93 int line, const char *value)
94{
95 size_t res_len, *dst_len;
96 char **dst, *tmp;
97
98 if (os_strcmp(value, "NULL") == 0) {
99 wpa_printf(MSG_DEBUG, "Unset configuration string '%s'",
100 data->name);
101 tmp = NULL;
102 res_len = 0;
103 goto set;
104 }
105
106 tmp = wpa_config_parse_string(value, &res_len);
107 if (tmp == NULL) {
108 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
109 line, data->name,
110 data->key_data ? "[KEY DATA REMOVED]" : value);
111 return -1;
112 }
113
114 if (data->key_data) {
115 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
116 (u8 *) tmp, res_len);
117 } else {
118 wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
119 (u8 *) tmp, res_len);
120 }
121
122 if (data->param3 && res_len < (size_t) data->param3) {
123 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
124 "min_len=%ld)", line, data->name,
125 (unsigned long) res_len, (long) data->param3);
126 os_free(tmp);
127 return -1;
128 }
129
130 if (data->param4 && res_len > (size_t) data->param4) {
131 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
132 "max_len=%ld)", line, data->name,
133 (unsigned long) res_len, (long) data->param4);
134 os_free(tmp);
135 return -1;
136 }
137
138set:
139 dst = (char **) (((u8 *) ssid) + (long) data->param1);
140 dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
141 os_free(*dst);
142 *dst = tmp;
143 if (data->param2)
144 *dst_len = res_len;
145
146 return 0;
147}
148
149
150#ifndef NO_CONFIG_WRITE
151static int is_hex(const u8 *data, size_t len)
152{
153 size_t i;
154
155 for (i = 0; i < len; i++) {
156 if (data[i] < 32 || data[i] >= 127)
157 return 1;
158 }
159 return 0;
160}
161
162
163static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
164{
165 char *buf;
166
167 buf = os_malloc(len + 3);
168 if (buf == NULL)
169 return NULL;
170 buf[0] = '"';
171 os_memcpy(buf + 1, value, len);
172 buf[len + 1] = '"';
173 buf[len + 2] = '\0';
174
175 return buf;
176}
177
178
179static char * wpa_config_write_string_hex(const u8 *value, size_t len)
180{
181 char *buf;
182
183 buf = os_zalloc(2 * len + 1);
184 if (buf == NULL)
185 return NULL;
186 wpa_snprintf_hex(buf, 2 * len + 1, value, len);
187
188 return buf;
189}
190
191
192static char * wpa_config_write_string(const u8 *value, size_t len)
193{
194 if (value == NULL)
195 return NULL;
196
197 if (is_hex(value, len))
198 return wpa_config_write_string_hex(value, len);
199 else
200 return wpa_config_write_string_ascii(value, len);
201}
202
203
204static char * wpa_config_write_str(const struct parse_data *data,
205 struct wpa_ssid *ssid)
206{
207 size_t len;
208 char **src;
209
210 src = (char **) (((u8 *) ssid) + (long) data->param1);
211 if (*src == NULL)
212 return NULL;
213
214 if (data->param2)
215 len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
216 else
217 len = os_strlen(*src);
218
219 return wpa_config_write_string((const u8 *) *src, len);
220}
Dmitry Shmidtc5da5d22011-07-15 15:32:26 -0700221
222#ifdef WPA_UNICODE_SSID
223static char * wpa_config_write_str_unicode(const struct parse_data *data,
224 struct wpa_ssid *ssid)
225{
226 size_t len;
227 char **src;
228
229 src = (char **) (((u8 *) ssid) + (long) data->param1);
230 if (*src == NULL)
231 return NULL;
232
233 if (data->param2)
234 len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
235 else
236 len = os_strlen(*src);
237
238 return wpa_config_write_string_ascii((const u8 *) *src, len);
239}
240#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -0700241#endif /* NO_CONFIG_WRITE */
242
243
244static int wpa_config_parse_int(const struct parse_data *data,
245 struct wpa_ssid *ssid,
246 int line, const char *value)
247{
248 int *dst;
249
250 dst = (int *) (((u8 *) ssid) + (long) data->param1);
251 *dst = atoi(value);
252 wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
253
254 if (data->param3 && *dst < (long) data->param3) {
255 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
256 "min_value=%ld)", line, data->name, *dst,
257 (long) data->param3);
258 *dst = (long) data->param3;
259 return -1;
260 }
261
262 if (data->param4 && *dst > (long) data->param4) {
263 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
264 "max_value=%ld)", line, data->name, *dst,
265 (long) data->param4);
266 *dst = (long) data->param4;
267 return -1;
268 }
269
270 return 0;
271}
272
273
274#ifndef NO_CONFIG_WRITE
275static char * wpa_config_write_int(const struct parse_data *data,
276 struct wpa_ssid *ssid)
277{
278 int *src, res;
279 char *value;
280
281 src = (int *) (((u8 *) ssid) + (long) data->param1);
282
283 value = os_malloc(20);
284 if (value == NULL)
285 return NULL;
286 res = os_snprintf(value, 20, "%d", *src);
287 if (res < 0 || res >= 20) {
288 os_free(value);
289 return NULL;
290 }
291 value[20 - 1] = '\0';
292 return value;
293}
294#endif /* NO_CONFIG_WRITE */
295
296
297static int wpa_config_parse_bssid(const struct parse_data *data,
298 struct wpa_ssid *ssid, int line,
299 const char *value)
300{
301 if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
302 os_strcmp(value, "any") == 0) {
303 ssid->bssid_set = 0;
304 wpa_printf(MSG_MSGDUMP, "BSSID any");
305 return 0;
306 }
307 if (hwaddr_aton(value, ssid->bssid)) {
308 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
309 line, value);
310 return -1;
311 }
312 ssid->bssid_set = 1;
313 wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
314 return 0;
315}
316
317
318#ifndef NO_CONFIG_WRITE
319static char * wpa_config_write_bssid(const struct parse_data *data,
320 struct wpa_ssid *ssid)
321{
322 char *value;
323 int res;
324
325 if (!ssid->bssid_set)
326 return NULL;
327
328 value = os_malloc(20);
329 if (value == NULL)
330 return NULL;
331 res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
332 if (res < 0 || res >= 20) {
333 os_free(value);
334 return NULL;
335 }
336 value[20 - 1] = '\0';
337 return value;
338}
339#endif /* NO_CONFIG_WRITE */
340
341
342static int wpa_config_parse_psk(const struct parse_data *data,
343 struct wpa_ssid *ssid, int line,
344 const char *value)
345{
346 if (*value == '"') {
347#ifndef CONFIG_NO_PBKDF2
348 const char *pos;
349 size_t len;
350
351 value++;
352 pos = os_strrchr(value, '"');
353 if (pos)
354 len = pos - value;
355 else
356 len = os_strlen(value);
357 if (len < 8 || len > 63) {
358 wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
359 "length %lu (expected: 8..63) '%s'.",
360 line, (unsigned long) len, value);
361 return -1;
362 }
363 wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
364 (u8 *) value, len);
365 if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
366 os_memcmp(ssid->passphrase, value, len) == 0)
367 return 0;
368 ssid->psk_set = 0;
369 os_free(ssid->passphrase);
370 ssid->passphrase = os_malloc(len + 1);
371 if (ssid->passphrase == NULL)
372 return -1;
373 os_memcpy(ssid->passphrase, value, len);
374 ssid->passphrase[len] = '\0';
375 return 0;
376#else /* CONFIG_NO_PBKDF2 */
377 wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
378 "supported.", line);
379 return -1;
380#endif /* CONFIG_NO_PBKDF2 */
381 }
382
383 if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
384 value[PMK_LEN * 2] != '\0') {
385 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
386 line, value);
387 return -1;
388 }
389
390 os_free(ssid->passphrase);
391 ssid->passphrase = NULL;
392
393 ssid->psk_set = 1;
394 wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
395 return 0;
396}
397
398
399#ifndef NO_CONFIG_WRITE
400static char * wpa_config_write_psk(const struct parse_data *data,
401 struct wpa_ssid *ssid)
402{
403 if (ssid->passphrase)
404 return wpa_config_write_string_ascii(
405 (const u8 *) ssid->passphrase,
406 os_strlen(ssid->passphrase));
407
408 if (ssid->psk_set)
409 return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
410
411 return NULL;
412}
413#endif /* NO_CONFIG_WRITE */
414
415
416static int wpa_config_parse_proto(const struct parse_data *data,
417 struct wpa_ssid *ssid, int line,
418 const char *value)
419{
420 int val = 0, last, errors = 0;
421 char *start, *end, *buf;
422
423 buf = os_strdup(value);
424 if (buf == NULL)
425 return -1;
426 start = buf;
427
428 while (*start != '\0') {
429 while (*start == ' ' || *start == '\t')
430 start++;
431 if (*start == '\0')
432 break;
433 end = start;
434 while (*end != ' ' && *end != '\t' && *end != '\0')
435 end++;
436 last = *end == '\0';
437 *end = '\0';
438 if (os_strcmp(start, "WPA") == 0)
439 val |= WPA_PROTO_WPA;
440 else if (os_strcmp(start, "RSN") == 0 ||
441 os_strcmp(start, "WPA2") == 0)
442 val |= WPA_PROTO_RSN;
443 else {
444 wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
445 line, start);
446 errors++;
447 }
448
449 if (last)
450 break;
451 start = end + 1;
452 }
453 os_free(buf);
454
455 if (val == 0) {
456 wpa_printf(MSG_ERROR,
457 "Line %d: no proto values configured.", line);
458 errors++;
459 }
460
461 wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
462 ssid->proto = val;
463 return errors ? -1 : 0;
464}
465
466
467#ifndef NO_CONFIG_WRITE
468static char * wpa_config_write_proto(const struct parse_data *data,
469 struct wpa_ssid *ssid)
470{
471 int first = 1, ret;
472 char *buf, *pos, *end;
473
474 pos = buf = os_zalloc(10);
475 if (buf == NULL)
476 return NULL;
477 end = buf + 10;
478
479 if (ssid->proto & WPA_PROTO_WPA) {
480 ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
481 if (ret < 0 || ret >= end - pos)
482 return buf;
483 pos += ret;
484 first = 0;
485 }
486
487 if (ssid->proto & WPA_PROTO_RSN) {
488 ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
489 if (ret < 0 || ret >= end - pos)
490 return buf;
491 pos += ret;
492 first = 0;
493 }
494
495 return buf;
496}
497#endif /* NO_CONFIG_WRITE */
498
499
500static int wpa_config_parse_key_mgmt(const struct parse_data *data,
501 struct wpa_ssid *ssid, int line,
502 const char *value)
503{
504 int val = 0, last, errors = 0;
505 char *start, *end, *buf;
506
507 buf = os_strdup(value);
508 if (buf == NULL)
509 return -1;
510 start = buf;
511
512 while (*start != '\0') {
513 while (*start == ' ' || *start == '\t')
514 start++;
515 if (*start == '\0')
516 break;
517 end = start;
518 while (*end != ' ' && *end != '\t' && *end != '\0')
519 end++;
520 last = *end == '\0';
521 *end = '\0';
522 if (os_strcmp(start, "WPA-PSK") == 0)
523 val |= WPA_KEY_MGMT_PSK;
524 else if (os_strcmp(start, "WPA-EAP") == 0)
525 val |= WPA_KEY_MGMT_IEEE8021X;
526 else if (os_strcmp(start, "IEEE8021X") == 0)
527 val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
528 else if (os_strcmp(start, "NONE") == 0)
529 val |= WPA_KEY_MGMT_NONE;
530 else if (os_strcmp(start, "WPA-NONE") == 0)
531 val |= WPA_KEY_MGMT_WPA_NONE;
532#ifdef CONFIG_IEEE80211R
533 else if (os_strcmp(start, "FT-PSK") == 0)
534 val |= WPA_KEY_MGMT_FT_PSK;
535 else if (os_strcmp(start, "FT-EAP") == 0)
536 val |= WPA_KEY_MGMT_FT_IEEE8021X;
537#endif /* CONFIG_IEEE80211R */
538#ifdef CONFIG_IEEE80211W
539 else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
540 val |= WPA_KEY_MGMT_PSK_SHA256;
541 else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
542 val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
543#endif /* CONFIG_IEEE80211W */
544#ifdef CONFIG_WPS
545 else if (os_strcmp(start, "WPS") == 0)
546 val |= WPA_KEY_MGMT_WPS;
547#endif /* CONFIG_WPS */
548 else {
549 wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
550 line, start);
551 errors++;
552 }
553
554 if (last)
555 break;
556 start = end + 1;
557 }
558 os_free(buf);
559
560 if (val == 0) {
561 wpa_printf(MSG_ERROR,
562 "Line %d: no key_mgmt values configured.", line);
563 errors++;
564 }
565
566 wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
567 ssid->key_mgmt = val;
568 return errors ? -1 : 0;
569}
570
571
572#ifndef NO_CONFIG_WRITE
573static char * wpa_config_write_key_mgmt(const struct parse_data *data,
574 struct wpa_ssid *ssid)
575{
576 char *buf, *pos, *end;
577 int ret;
578
579 pos = buf = os_zalloc(50);
580 if (buf == NULL)
581 return NULL;
582 end = buf + 50;
583
584 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
585 ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
586 pos == buf ? "" : " ");
587 if (ret < 0 || ret >= end - pos) {
588 end[-1] = '\0';
589 return buf;
590 }
591 pos += ret;
592 }
593
594 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
595 ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
596 pos == buf ? "" : " ");
597 if (ret < 0 || ret >= end - pos) {
598 end[-1] = '\0';
599 return buf;
600 }
601 pos += ret;
602 }
603
604 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
605 ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
606 pos == buf ? "" : " ");
607 if (ret < 0 || ret >= end - pos) {
608 end[-1] = '\0';
609 return buf;
610 }
611 pos += ret;
612 }
613
614 if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
615 ret = os_snprintf(pos, end - pos, "%sNONE",
616 pos == buf ? "" : " ");
617 if (ret < 0 || ret >= end - pos) {
618 end[-1] = '\0';
619 return buf;
620 }
621 pos += ret;
622 }
623
624 if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
625 ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
626 pos == buf ? "" : " ");
627 if (ret < 0 || ret >= end - pos) {
628 end[-1] = '\0';
629 return buf;
630 }
631 pos += ret;
632 }
633
634#ifdef CONFIG_IEEE80211R
635 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
636 pos += os_snprintf(pos, end - pos, "%sFT-PSK",
637 pos == buf ? "" : " ");
638
639 if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
640 pos += os_snprintf(pos, end - pos, "%sFT-EAP",
641 pos == buf ? "" : " ");
642#endif /* CONFIG_IEEE80211R */
643
644#ifdef CONFIG_IEEE80211W
645 if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
646 pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
647 pos == buf ? "" : " ");
648
649 if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
650 pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
651 pos == buf ? "" : " ");
652#endif /* CONFIG_IEEE80211W */
653
654#ifdef CONFIG_WPS
655 if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
656 pos += os_snprintf(pos, end - pos, "%sWPS",
657 pos == buf ? "" : " ");
658#endif /* CONFIG_WPS */
659
660 return buf;
661}
662#endif /* NO_CONFIG_WRITE */
663
664
665static int wpa_config_parse_cipher(int line, const char *value)
666{
667 int val = 0, last;
668 char *start, *end, *buf;
669
670 buf = os_strdup(value);
671 if (buf == NULL)
672 return -1;
673 start = buf;
674
675 while (*start != '\0') {
676 while (*start == ' ' || *start == '\t')
677 start++;
678 if (*start == '\0')
679 break;
680 end = start;
681 while (*end != ' ' && *end != '\t' && *end != '\0')
682 end++;
683 last = *end == '\0';
684 *end = '\0';
685 if (os_strcmp(start, "CCMP") == 0)
686 val |= WPA_CIPHER_CCMP;
687 else if (os_strcmp(start, "TKIP") == 0)
688 val |= WPA_CIPHER_TKIP;
689 else if (os_strcmp(start, "WEP104") == 0)
690 val |= WPA_CIPHER_WEP104;
691 else if (os_strcmp(start, "WEP40") == 0)
692 val |= WPA_CIPHER_WEP40;
693 else if (os_strcmp(start, "NONE") == 0)
694 val |= WPA_CIPHER_NONE;
695 else {
696 wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
697 line, start);
698 os_free(buf);
699 return -1;
700 }
701
702 if (last)
703 break;
704 start = end + 1;
705 }
706 os_free(buf);
707
708 if (val == 0) {
709 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
710 line);
711 return -1;
712 }
713 return val;
714}
715
716
717#ifndef NO_CONFIG_WRITE
718static char * wpa_config_write_cipher(int cipher)
719{
720 char *buf, *pos, *end;
721 int ret;
722
723 pos = buf = os_zalloc(50);
724 if (buf == NULL)
725 return NULL;
726 end = buf + 50;
727
728 if (cipher & WPA_CIPHER_CCMP) {
729 ret = os_snprintf(pos, end - pos, "%sCCMP",
730 pos == buf ? "" : " ");
731 if (ret < 0 || ret >= end - pos) {
732 end[-1] = '\0';
733 return buf;
734 }
735 pos += ret;
736 }
737
738 if (cipher & WPA_CIPHER_TKIP) {
739 ret = os_snprintf(pos, end - pos, "%sTKIP",
740 pos == buf ? "" : " ");
741 if (ret < 0 || ret >= end - pos) {
742 end[-1] = '\0';
743 return buf;
744 }
745 pos += ret;
746 }
747
748 if (cipher & WPA_CIPHER_WEP104) {
749 ret = os_snprintf(pos, end - pos, "%sWEP104",
750 pos == buf ? "" : " ");
751 if (ret < 0 || ret >= end - pos) {
752 end[-1] = '\0';
753 return buf;
754 }
755 pos += ret;
756 }
757
758 if (cipher & WPA_CIPHER_WEP40) {
759 ret = os_snprintf(pos, end - pos, "%sWEP40",
760 pos == buf ? "" : " ");
761 if (ret < 0 || ret >= end - pos) {
762 end[-1] = '\0';
763 return buf;
764 }
765 pos += ret;
766 }
767
768 if (cipher & WPA_CIPHER_NONE) {
769 ret = os_snprintf(pos, end - pos, "%sNONE",
770 pos == buf ? "" : " ");
771 if (ret < 0 || ret >= end - pos) {
772 end[-1] = '\0';
773 return buf;
774 }
775 pos += ret;
776 }
777
778 return buf;
779}
780#endif /* NO_CONFIG_WRITE */
781
782
783static int wpa_config_parse_pairwise(const struct parse_data *data,
784 struct wpa_ssid *ssid, int line,
785 const char *value)
786{
787 int val;
788 val = wpa_config_parse_cipher(line, value);
789 if (val == -1)
790 return -1;
791 if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
792 wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
793 "(0x%x).", line, val);
794 return -1;
795 }
796
797 wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
798 ssid->pairwise_cipher = val;
799 return 0;
800}
801
802
803#ifndef NO_CONFIG_WRITE
804static char * wpa_config_write_pairwise(const struct parse_data *data,
805 struct wpa_ssid *ssid)
806{
807 return wpa_config_write_cipher(ssid->pairwise_cipher);
808}
809#endif /* NO_CONFIG_WRITE */
810
811
812static int wpa_config_parse_group(const struct parse_data *data,
813 struct wpa_ssid *ssid, int line,
814 const char *value)
815{
816 int val;
817 val = wpa_config_parse_cipher(line, value);
818 if (val == -1)
819 return -1;
820 if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
821 WPA_CIPHER_WEP40)) {
822 wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
823 "(0x%x).", line, val);
824 return -1;
825 }
826
827 wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
828 ssid->group_cipher = val;
829 return 0;
830}
831
832
833#ifndef NO_CONFIG_WRITE
834static char * wpa_config_write_group(const struct parse_data *data,
835 struct wpa_ssid *ssid)
836{
837 return wpa_config_write_cipher(ssid->group_cipher);
838}
839#endif /* NO_CONFIG_WRITE */
840
841
842static int wpa_config_parse_auth_alg(const struct parse_data *data,
843 struct wpa_ssid *ssid, int line,
844 const char *value)
845{
846 int val = 0, last, errors = 0;
847 char *start, *end, *buf;
848
849 buf = os_strdup(value);
850 if (buf == NULL)
851 return -1;
852 start = buf;
853
854 while (*start != '\0') {
855 while (*start == ' ' || *start == '\t')
856 start++;
857 if (*start == '\0')
858 break;
859 end = start;
860 while (*end != ' ' && *end != '\t' && *end != '\0')
861 end++;
862 last = *end == '\0';
863 *end = '\0';
864 if (os_strcmp(start, "OPEN") == 0)
865 val |= WPA_AUTH_ALG_OPEN;
866 else if (os_strcmp(start, "SHARED") == 0)
867 val |= WPA_AUTH_ALG_SHARED;
868 else if (os_strcmp(start, "LEAP") == 0)
869 val |= WPA_AUTH_ALG_LEAP;
870 else {
871 wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
872 line, start);
873 errors++;
874 }
875
876 if (last)
877 break;
878 start = end + 1;
879 }
880 os_free(buf);
881
882 if (val == 0) {
883 wpa_printf(MSG_ERROR,
884 "Line %d: no auth_alg values configured.", line);
885 errors++;
886 }
887
888 wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
889 ssid->auth_alg = val;
890 return errors ? -1 : 0;
891}
892
893
894#ifndef NO_CONFIG_WRITE
895static char * wpa_config_write_auth_alg(const struct parse_data *data,
896 struct wpa_ssid *ssid)
897{
898 char *buf, *pos, *end;
899 int ret;
900
901 pos = buf = os_zalloc(30);
902 if (buf == NULL)
903 return NULL;
904 end = buf + 30;
905
906 if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
907 ret = os_snprintf(pos, end - pos, "%sOPEN",
908 pos == buf ? "" : " ");
909 if (ret < 0 || ret >= end - pos) {
910 end[-1] = '\0';
911 return buf;
912 }
913 pos += ret;
914 }
915
916 if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
917 ret = os_snprintf(pos, end - pos, "%sSHARED",
918 pos == buf ? "" : " ");
919 if (ret < 0 || ret >= end - pos) {
920 end[-1] = '\0';
921 return buf;
922 }
923 pos += ret;
924 }
925
926 if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
927 ret = os_snprintf(pos, end - pos, "%sLEAP",
928 pos == buf ? "" : " ");
929 if (ret < 0 || ret >= end - pos) {
930 end[-1] = '\0';
931 return buf;
932 }
933 pos += ret;
934 }
935
936 return buf;
937}
938#endif /* NO_CONFIG_WRITE */
939
940
941static int * wpa_config_parse_freqs(const struct parse_data *data,
942 struct wpa_ssid *ssid, int line,
943 const char *value)
944{
945 int *freqs;
946 size_t used, len;
947 const char *pos;
948
949 used = 0;
950 len = 10;
951 freqs = os_zalloc((len + 1) * sizeof(int));
952 if (freqs == NULL)
953 return NULL;
954
955 pos = value;
956 while (pos) {
957 while (*pos == ' ')
958 pos++;
959 if (used == len) {
960 int *n;
961 size_t i;
962 n = os_realloc(freqs, (len * 2 + 1) * sizeof(int));
963 if (n == NULL) {
964 os_free(freqs);
965 return NULL;
966 }
967 for (i = len; i <= len * 2; i++)
968 n[i] = 0;
969 freqs = n;
970 len *= 2;
971 }
972
973 freqs[used] = atoi(pos);
974 if (freqs[used] == 0)
975 break;
976 used++;
977 pos = os_strchr(pos + 1, ' ');
978 }
979
980 return freqs;
981}
982
983
984static int wpa_config_parse_scan_freq(const struct parse_data *data,
985 struct wpa_ssid *ssid, int line,
986 const char *value)
987{
988 int *freqs;
989
990 freqs = wpa_config_parse_freqs(data, ssid, line, value);
991 if (freqs == NULL)
992 return -1;
993 os_free(ssid->scan_freq);
994 ssid->scan_freq = freqs;
995
996 return 0;
997}
998
999
1000static int wpa_config_parse_freq_list(const struct parse_data *data,
1001 struct wpa_ssid *ssid, int line,
1002 const char *value)
1003{
1004 int *freqs;
1005
1006 freqs = wpa_config_parse_freqs(data, ssid, line, value);
1007 if (freqs == NULL)
1008 return -1;
1009 os_free(ssid->freq_list);
1010 ssid->freq_list = freqs;
1011
1012 return 0;
1013}
1014
1015
1016#ifndef NO_CONFIG_WRITE
1017static char * wpa_config_write_freqs(const struct parse_data *data,
1018 const int *freqs)
1019{
1020 char *buf, *pos, *end;
1021 int i, ret;
1022 size_t count;
1023
1024 if (freqs == NULL)
1025 return NULL;
1026
1027 count = 0;
1028 for (i = 0; freqs[i]; i++)
1029 count++;
1030
1031 pos = buf = os_zalloc(10 * count + 1);
1032 if (buf == NULL)
1033 return NULL;
1034 end = buf + 10 * count + 1;
1035
1036 for (i = 0; freqs[i]; i++) {
1037 ret = os_snprintf(pos, end - pos, "%s%u",
1038 i == 0 ? "" : " ", freqs[i]);
1039 if (ret < 0 || ret >= end - pos) {
1040 end[-1] = '\0';
1041 return buf;
1042 }
1043 pos += ret;
1044 }
1045
1046 return buf;
1047}
1048
1049
1050static char * wpa_config_write_scan_freq(const struct parse_data *data,
1051 struct wpa_ssid *ssid)
1052{
1053 return wpa_config_write_freqs(data, ssid->scan_freq);
1054}
1055
1056
1057static char * wpa_config_write_freq_list(const struct parse_data *data,
1058 struct wpa_ssid *ssid)
1059{
1060 return wpa_config_write_freqs(data, ssid->freq_list);
1061}
1062#endif /* NO_CONFIG_WRITE */
1063
1064
1065#ifdef IEEE8021X_EAPOL
1066static int wpa_config_parse_eap(const struct parse_data *data,
1067 struct wpa_ssid *ssid, int line,
1068 const char *value)
1069{
1070 int last, errors = 0;
1071 char *start, *end, *buf;
1072 struct eap_method_type *methods = NULL, *tmp;
1073 size_t num_methods = 0;
1074
1075 buf = os_strdup(value);
1076 if (buf == NULL)
1077 return -1;
1078 start = buf;
1079
1080 while (*start != '\0') {
1081 while (*start == ' ' || *start == '\t')
1082 start++;
1083 if (*start == '\0')
1084 break;
1085 end = start;
1086 while (*end != ' ' && *end != '\t' && *end != '\0')
1087 end++;
1088 last = *end == '\0';
1089 *end = '\0';
1090 tmp = methods;
1091 methods = os_realloc(methods,
1092 (num_methods + 1) * sizeof(*methods));
1093 if (methods == NULL) {
1094 os_free(tmp);
1095 os_free(buf);
1096 return -1;
1097 }
1098 methods[num_methods].method = eap_peer_get_type(
1099 start, &methods[num_methods].vendor);
1100 if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1101 methods[num_methods].method == EAP_TYPE_NONE) {
1102 wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
1103 "'%s'", line, start);
1104 wpa_printf(MSG_ERROR, "You may need to add support for"
1105 " this EAP method during wpa_supplicant\n"
1106 "build time configuration.\n"
1107 "See README for more information.");
1108 errors++;
1109 } else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
1110 methods[num_methods].method == EAP_TYPE_LEAP)
1111 ssid->leap++;
1112 else
1113 ssid->non_leap++;
1114 num_methods++;
1115 if (last)
1116 break;
1117 start = end + 1;
1118 }
1119 os_free(buf);
1120
1121 tmp = methods;
1122 methods = os_realloc(methods, (num_methods + 1) * sizeof(*methods));
1123 if (methods == NULL) {
1124 os_free(tmp);
1125 return -1;
1126 }
1127 methods[num_methods].vendor = EAP_VENDOR_IETF;
1128 methods[num_methods].method = EAP_TYPE_NONE;
1129 num_methods++;
1130
1131 wpa_hexdump(MSG_MSGDUMP, "eap methods",
1132 (u8 *) methods, num_methods * sizeof(*methods));
1133 ssid->eap.eap_methods = methods;
1134 return errors ? -1 : 0;
1135}
1136
1137
1138static char * wpa_config_write_eap(const struct parse_data *data,
1139 struct wpa_ssid *ssid)
1140{
1141 int i, ret;
1142 char *buf, *pos, *end;
1143 const struct eap_method_type *eap_methods = ssid->eap.eap_methods;
1144 const char *name;
1145
1146 if (eap_methods == NULL)
1147 return NULL;
1148
1149 pos = buf = os_zalloc(100);
1150 if (buf == NULL)
1151 return NULL;
1152 end = buf + 100;
1153
1154 for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
1155 eap_methods[i].method != EAP_TYPE_NONE; i++) {
1156 name = eap_get_name(eap_methods[i].vendor,
1157 eap_methods[i].method);
1158 if (name) {
1159 ret = os_snprintf(pos, end - pos, "%s%s",
1160 pos == buf ? "" : " ", name);
1161 if (ret < 0 || ret >= end - pos)
1162 break;
1163 pos += ret;
1164 }
1165 }
1166
1167 end[-1] = '\0';
1168
1169 return buf;
1170}
1171
1172
1173static int wpa_config_parse_password(const struct parse_data *data,
1174 struct wpa_ssid *ssid, int line,
1175 const char *value)
1176{
1177 u8 *hash;
1178
1179 if (os_strcmp(value, "NULL") == 0) {
1180 wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
1181 os_free(ssid->eap.password);
1182 ssid->eap.password = NULL;
1183 ssid->eap.password_len = 0;
1184 return 0;
1185 }
1186
1187 if (os_strncmp(value, "hash:", 5) != 0) {
1188 char *tmp;
1189 size_t res_len;
1190
1191 tmp = wpa_config_parse_string(value, &res_len);
1192 if (tmp == NULL) {
1193 wpa_printf(MSG_ERROR, "Line %d: failed to parse "
1194 "password.", line);
1195 return -1;
1196 }
1197 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
1198 (u8 *) tmp, res_len);
1199
1200 os_free(ssid->eap.password);
1201 ssid->eap.password = (u8 *) tmp;
1202 ssid->eap.password_len = res_len;
1203 ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1204
1205 return 0;
1206 }
1207
1208
1209 /* NtPasswordHash: hash:<32 hex digits> */
1210 if (os_strlen(value + 5) != 2 * 16) {
1211 wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
1212 "(expected 32 hex digits)", line);
1213 return -1;
1214 }
1215
1216 hash = os_malloc(16);
1217 if (hash == NULL)
1218 return -1;
1219
1220 if (hexstr2bin(value + 5, hash, 16)) {
1221 os_free(hash);
1222 wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
1223 return -1;
1224 }
1225
1226 wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
1227
1228 os_free(ssid->eap.password);
1229 ssid->eap.password = hash;
1230 ssid->eap.password_len = 16;
1231 ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
1232
1233 return 0;
1234}
1235
1236
1237static char * wpa_config_write_password(const struct parse_data *data,
1238 struct wpa_ssid *ssid)
1239{
1240 char *buf;
1241
1242 if (ssid->eap.password == NULL)
1243 return NULL;
1244
1245 if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
1246 return wpa_config_write_string(
1247 ssid->eap.password, ssid->eap.password_len);
1248 }
1249
1250 buf = os_malloc(5 + 32 + 1);
1251 if (buf == NULL)
1252 return NULL;
1253
1254 os_memcpy(buf, "hash:", 5);
1255 wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16);
1256
1257 return buf;
1258}
1259#endif /* IEEE8021X_EAPOL */
1260
1261
1262static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
1263 const char *value, int idx)
1264{
1265 char *buf, title[20];
1266 int res;
1267
1268 buf = wpa_config_parse_string(value, len);
1269 if (buf == NULL) {
1270 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
1271 line, idx, value);
1272 return -1;
1273 }
1274 if (*len > MAX_WEP_KEY_LEN) {
1275 wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
1276 line, idx, value);
1277 os_free(buf);
1278 return -1;
1279 }
1280 os_memcpy(key, buf, *len);
1281 os_free(buf);
1282 res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
1283 if (res >= 0 && (size_t) res < sizeof(title))
1284 wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
1285 return 0;
1286}
1287
1288
1289static int wpa_config_parse_wep_key0(const struct parse_data *data,
1290 struct wpa_ssid *ssid, int line,
1291 const char *value)
1292{
1293 return wpa_config_parse_wep_key(ssid->wep_key[0],
1294 &ssid->wep_key_len[0], line,
1295 value, 0);
1296}
1297
1298
1299static int wpa_config_parse_wep_key1(const struct parse_data *data,
1300 struct wpa_ssid *ssid, int line,
1301 const char *value)
1302{
1303 return wpa_config_parse_wep_key(ssid->wep_key[1],
1304 &ssid->wep_key_len[1], line,
1305 value, 1);
1306}
1307
1308
1309static int wpa_config_parse_wep_key2(const struct parse_data *data,
1310 struct wpa_ssid *ssid, int line,
1311 const char *value)
1312{
1313 return wpa_config_parse_wep_key(ssid->wep_key[2],
1314 &ssid->wep_key_len[2], line,
1315 value, 2);
1316}
1317
1318
1319static int wpa_config_parse_wep_key3(const struct parse_data *data,
1320 struct wpa_ssid *ssid, int line,
1321 const char *value)
1322{
1323 return wpa_config_parse_wep_key(ssid->wep_key[3],
1324 &ssid->wep_key_len[3], line,
1325 value, 3);
1326}
1327
1328
1329#ifndef NO_CONFIG_WRITE
1330static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
1331{
1332 if (ssid->wep_key_len[idx] == 0)
1333 return NULL;
1334 return wpa_config_write_string(ssid->wep_key[idx],
1335 ssid->wep_key_len[idx]);
1336}
1337
1338
1339static char * wpa_config_write_wep_key0(const struct parse_data *data,
1340 struct wpa_ssid *ssid)
1341{
1342 return wpa_config_write_wep_key(ssid, 0);
1343}
1344
1345
1346static char * wpa_config_write_wep_key1(const struct parse_data *data,
1347 struct wpa_ssid *ssid)
1348{
1349 return wpa_config_write_wep_key(ssid, 1);
1350}
1351
1352
1353static char * wpa_config_write_wep_key2(const struct parse_data *data,
1354 struct wpa_ssid *ssid)
1355{
1356 return wpa_config_write_wep_key(ssid, 2);
1357}
1358
1359
1360static char * wpa_config_write_wep_key3(const struct parse_data *data,
1361 struct wpa_ssid *ssid)
1362{
1363 return wpa_config_write_wep_key(ssid, 3);
1364}
1365#endif /* NO_CONFIG_WRITE */
1366
1367
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001368#ifdef CONFIG_P2P
1369
1370static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
1371 struct wpa_ssid *ssid, int line,
1372 const char *value)
1373{
1374 const char *pos;
1375 u8 *buf, *n, addr[ETH_ALEN];
1376 size_t count;
1377
1378 buf = NULL;
1379 count = 0;
1380
1381 pos = value;
1382 while (pos && *pos) {
1383 while (*pos == ' ')
1384 pos++;
1385
1386 if (hwaddr_aton(pos, addr)) {
1387 wpa_printf(MSG_ERROR, "Line %d: Invalid "
1388 "p2p_client_list address '%s'.",
1389 line, value);
1390 /* continue anyway */
1391 } else {
1392 n = os_realloc(buf, (count + 1) * ETH_ALEN);
1393 if (n == NULL) {
1394 os_free(buf);
1395 return -1;
1396 }
1397 buf = n;
1398 os_memcpy(buf + count * ETH_ALEN, addr, ETH_ALEN);
1399 count++;
1400 wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
1401 addr, ETH_ALEN);
1402 }
1403
1404 pos = os_strchr(pos, ' ');
1405 }
1406
1407 os_free(ssid->p2p_client_list);
1408 ssid->p2p_client_list = buf;
1409 ssid->num_p2p_clients = count;
1410
1411 return 0;
1412}
1413
1414
1415#ifndef NO_CONFIG_WRITE
1416static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
1417 struct wpa_ssid *ssid)
1418{
1419 char *value, *end, *pos;
1420 int res;
1421 size_t i;
1422
1423 if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
1424 return NULL;
1425
1426 value = os_malloc(20 * ssid->num_p2p_clients);
1427 if (value == NULL)
1428 return NULL;
1429 pos = value;
1430 end = value + 20 * ssid->num_p2p_clients;
1431
1432 for (i = 0; i < ssid->num_p2p_clients; i++) {
1433 res = os_snprintf(pos, end - pos, MACSTR " ",
1434 MAC2STR(ssid->p2p_client_list +
1435 i * ETH_ALEN));
1436 if (res < 0 || res >= end - pos) {
1437 os_free(value);
1438 return NULL;
1439 }
1440 pos += res;
1441 }
1442
1443 if (pos > value)
1444 pos[-1] = '\0';
1445
1446 return value;
1447}
1448#endif /* NO_CONFIG_WRITE */
1449
1450#endif /* CONFIG_P2P */
1451
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001452/* Helper macros for network block parser */
1453
1454#ifdef OFFSET
1455#undef OFFSET
1456#endif /* OFFSET */
1457/* OFFSET: Get offset of a variable within the wpa_ssid structure */
1458#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
1459
1460/* STR: Define a string variable for an ASCII string; f = field name */
1461#ifdef NO_CONFIG_WRITE
1462#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
1463#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
1464#else /* NO_CONFIG_WRITE */
1465#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
1466#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
1467#endif /* NO_CONFIG_WRITE */
1468#define STR(f) _STR(f), NULL, NULL, NULL, 0
1469#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
1470#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
1471#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
1472
1473/* STR_LEN: Define a string variable with a separate variable for storing the
1474 * data length. Unlike STR(), this can be used to store arbitrary binary data
1475 * (i.e., even nul termination character). */
1476#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
1477#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
1478#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
1479#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
1480#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
1481
1482/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
1483 * explicitly specified. */
1484#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
1485#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
1486#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
1487
1488#ifdef NO_CONFIG_WRITE
1489#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
1490#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
1491#else /* NO_CONFIG_WRITE */
1492#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
1493 OFFSET(f), (void *) 0
1494#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
1495 OFFSET(eap.f), (void *) 0
Dmitry Shmidtc5da5d22011-07-15 15:32:26 -07001496#ifdef WPA_UNICODE_SSID
1497/* STR_* variants that do not force conversion to ASCII */
1498#define _STR_UNICODE(f) #f, wpa_config_parse_str, wpa_config_write_str_unicode, OFFSET(f)
1499#define STR_UNICODE(f) _STR_UNICODE(f), NULL, NULL, NULL, 0
1500#define _STR_LEN_UNICODE(f) _STR_UNICODE(f), OFFSET(f ## _len)
1501#define STR_LEN_UNICODE(f) _STR_LEN_UNICODE(f), NULL, NULL, 0
1502#define _STR_RANGE_UNICODE(f, min, max) _STR_LEN_UNICODE(f), (void *) (min), (void *) (max)
1503#define STR_RANGE_UNICODE(f, min, max) _STR_RANGE_UNICODE(f, min, max), 0
1504#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001505#endif /* NO_CONFIG_WRITE */
1506
1507/* INT: Define an integer variable */
1508#define INT(f) _INT(f), NULL, NULL, 0
1509#define INTe(f) _INTe(f), NULL, NULL, 0
1510
1511/* INT_RANGE: Define an integer variable with allowed value range */
1512#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
1513
1514/* FUNC: Define a configuration variable that uses a custom function for
1515 * parsing and writing the value. */
1516#ifdef NO_CONFIG_WRITE
1517#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL
1518#else /* NO_CONFIG_WRITE */
1519#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
1520 NULL, NULL, NULL, NULL
1521#endif /* NO_CONFIG_WRITE */
1522#define FUNC(f) _FUNC(f), 0
1523#define FUNC_KEY(f) _FUNC(f), 1
1524
1525/*
1526 * Table of network configuration variables. This table is used to parse each
1527 * network configuration variable, e.g., each line in wpa_supplicant.conf file
1528 * that is inside a network block.
1529 *
1530 * This table is generated using the helper macros defined above and with
1531 * generous help from the C pre-processor. The field name is stored as a string
1532 * into .name and for STR and INT types, the offset of the target buffer within
1533 * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
1534 * offset to the field containing the length of the configuration variable.
1535 * .param3 and .param4 can be used to mark the allowed range (length for STR
1536 * and value for INT).
1537 *
1538 * For each configuration line in wpa_supplicant.conf, the parser goes through
1539 * this table and select the entry that matches with the field name. The parser
1540 * function (.parser) is then called to parse the actual value of the field.
1541 *
1542 * This kind of mechanism makes it easy to add new configuration parameters,
1543 * since only one line needs to be added into this table and into the
1544 * struct wpa_ssid definition if the new variable is either a string or
1545 * integer. More complex types will need to use their own parser and writer
1546 * functions.
1547 */
1548static const struct parse_data ssid_fields[] = {
Dmitry Shmidtc5da5d22011-07-15 15:32:26 -07001549#ifdef WPA_UNICODE_SSID
1550 { STR_RANGE_UNICODE(ssid, 0, MAX_SSID_LEN) },
1551#else
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001552 { STR_RANGE(ssid, 0, MAX_SSID_LEN) },
Dmitry Shmidtc5da5d22011-07-15 15:32:26 -07001553#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001554 { INT_RANGE(scan_ssid, 0, 1) },
1555 { FUNC(bssid) },
1556 { FUNC_KEY(psk) },
1557 { FUNC(proto) },
1558 { FUNC(key_mgmt) },
1559 { FUNC(pairwise) },
1560 { FUNC(group) },
1561 { FUNC(auth_alg) },
1562 { FUNC(scan_freq) },
1563 { FUNC(freq_list) },
1564#ifdef IEEE8021X_EAPOL
1565 { FUNC(eap) },
1566 { STR_LENe(identity) },
1567 { STR_LENe(anonymous_identity) },
1568 { FUNC_KEY(password) },
1569 { STRe(ca_cert) },
1570 { STRe(ca_path) },
1571 { STRe(client_cert) },
1572 { STRe(private_key) },
1573 { STR_KEYe(private_key_passwd) },
1574 { STRe(dh_file) },
1575 { STRe(subject_match) },
1576 { STRe(altsubject_match) },
1577 { STRe(ca_cert2) },
1578 { STRe(ca_path2) },
1579 { STRe(client_cert2) },
1580 { STRe(private_key2) },
1581 { STR_KEYe(private_key2_passwd) },
1582 { STRe(dh_file2) },
1583 { STRe(subject_match2) },
1584 { STRe(altsubject_match2) },
1585 { STRe(phase1) },
1586 { STRe(phase2) },
1587 { STRe(pcsc) },
1588 { STR_KEYe(pin) },
1589 { STRe(engine_id) },
1590 { STRe(key_id) },
1591 { STRe(cert_id) },
1592 { STRe(ca_cert_id) },
1593 { STR_KEYe(pin2) },
1594 { STRe(engine2_id) },
1595 { STRe(key2_id) },
1596 { STRe(cert2_id) },
1597 { STRe(ca_cert2_id) },
1598 { INTe(engine) },
1599 { INTe(engine2) },
1600 { INT(eapol_flags) },
1601#endif /* IEEE8021X_EAPOL */
1602 { FUNC_KEY(wep_key0) },
1603 { FUNC_KEY(wep_key1) },
1604 { FUNC_KEY(wep_key2) },
1605 { FUNC_KEY(wep_key3) },
1606 { INT(wep_tx_keyidx) },
1607 { INT(priority) },
1608#ifdef IEEE8021X_EAPOL
1609 { INT(eap_workaround) },
1610 { STRe(pac_file) },
1611 { INTe(fragment_size) },
1612#endif /* IEEE8021X_EAPOL */
1613 { INT_RANGE(mode, 0, 4) },
1614 { INT_RANGE(proactive_key_caching, 0, 1) },
1615 { INT_RANGE(disabled, 0, 2) },
1616 { STR(id_str) },
1617#ifdef CONFIG_IEEE80211W
1618 { INT_RANGE(ieee80211w, 0, 2) },
1619#endif /* CONFIG_IEEE80211W */
1620 { INT_RANGE(peerkey, 0, 1) },
1621 { INT_RANGE(mixed_cell, 0, 1) },
1622 { INT_RANGE(frequency, 0, 10000) },
1623 { INT(wpa_ptk_rekey) },
1624 { STR(bgscan) },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001625#ifdef CONFIG_P2P
1626 { FUNC(p2p_client_list) },
1627#endif /* CONFIG_P2P */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001628#ifdef CONFIG_HT_OVERRIDES
1629 { INT_RANGE(disable_ht, 0, 1) },
1630 { INT_RANGE(disable_ht40, -1, 1) },
1631 { INT_RANGE(disable_max_amsdu, -1, 1) },
1632 { INT_RANGE(ampdu_factor, -1, 3) },
1633 { INT_RANGE(ampdu_density, -1, 7) },
1634 { STR(ht_mcs) },
1635#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001636};
1637
Dmitry Shmidtc5da5d22011-07-15 15:32:26 -07001638#ifdef WPA_UNICODE_SSID
1639#undef _STR_UNICODE
1640#undef STR_UNICODE
1641#undef _STR_LEN_UNICODE
1642#undef STR_LEN_UNICODE
1643#undef _STR_RANGE_UNICODE
1644#undef STR_RANGE_UNICODE
1645#endif
1646
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001647#undef OFFSET
1648#undef _STR
1649#undef STR
1650#undef STR_KEY
1651#undef _STR_LEN
1652#undef STR_LEN
1653#undef STR_LEN_KEY
1654#undef _STR_RANGE
1655#undef STR_RANGE
1656#undef STR_RANGE_KEY
1657#undef _INT
1658#undef INT
1659#undef INT_RANGE
1660#undef _FUNC
1661#undef FUNC
1662#undef FUNC_KEY
1663#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
1664
1665
1666/**
1667 * wpa_config_add_prio_network - Add a network to priority lists
1668 * @config: Configuration data from wpa_config_read()
1669 * @ssid: Pointer to the network configuration to be added to the list
1670 * Returns: 0 on success, -1 on failure
1671 *
1672 * This function is used to add a network block to the priority list of
1673 * networks. This must be called for each network when reading in the full
1674 * configuration. In addition, this can be used indirectly when updating
1675 * priorities by calling wpa_config_update_prio_list().
1676 */
1677int wpa_config_add_prio_network(struct wpa_config *config,
1678 struct wpa_ssid *ssid)
1679{
1680 int prio;
1681 struct wpa_ssid *prev, **nlist;
1682
1683 /*
1684 * Add to an existing priority list if one is available for the
1685 * configured priority level for this network.
1686 */
1687 for (prio = 0; prio < config->num_prio; prio++) {
1688 prev = config->pssid[prio];
1689 if (prev->priority == ssid->priority) {
1690 while (prev->pnext)
1691 prev = prev->pnext;
1692 prev->pnext = ssid;
1693 return 0;
1694 }
1695 }
1696
1697 /* First network for this priority - add a new priority list */
1698 nlist = os_realloc(config->pssid,
1699 (config->num_prio + 1) * sizeof(struct wpa_ssid *));
1700 if (nlist == NULL)
1701 return -1;
1702
1703 for (prio = 0; prio < config->num_prio; prio++) {
1704 if (nlist[prio]->priority < ssid->priority)
1705 break;
1706 }
1707
1708 os_memmove(&nlist[prio + 1], &nlist[prio],
1709 (config->num_prio - prio) * sizeof(struct wpa_ssid *));
1710
1711 nlist[prio] = ssid;
1712 config->num_prio++;
1713 config->pssid = nlist;
1714
1715 return 0;
1716}
1717
1718
1719/**
1720 * wpa_config_update_prio_list - Update network priority list
1721 * @config: Configuration data from wpa_config_read()
1722 * Returns: 0 on success, -1 on failure
1723 *
1724 * This function is called to update the priority list of networks in the
1725 * configuration when a network is being added or removed. This is also called
1726 * if a priority for a network is changed.
1727 */
1728int wpa_config_update_prio_list(struct wpa_config *config)
1729{
1730 struct wpa_ssid *ssid;
1731 int ret = 0;
1732
1733 os_free(config->pssid);
1734 config->pssid = NULL;
1735 config->num_prio = 0;
1736
1737 ssid = config->ssid;
1738 while (ssid) {
1739 ssid->pnext = NULL;
1740 if (wpa_config_add_prio_network(config, ssid) < 0)
1741 ret = -1;
1742 ssid = ssid->next;
1743 }
1744
1745 return ret;
1746}
1747
1748
1749#ifdef IEEE8021X_EAPOL
1750static void eap_peer_config_free(struct eap_peer_config *eap)
1751{
1752 os_free(eap->eap_methods);
1753 os_free(eap->identity);
1754 os_free(eap->anonymous_identity);
1755 os_free(eap->password);
1756 os_free(eap->ca_cert);
1757 os_free(eap->ca_path);
1758 os_free(eap->client_cert);
1759 os_free(eap->private_key);
1760 os_free(eap->private_key_passwd);
1761 os_free(eap->dh_file);
1762 os_free(eap->subject_match);
1763 os_free(eap->altsubject_match);
1764 os_free(eap->ca_cert2);
1765 os_free(eap->ca_path2);
1766 os_free(eap->client_cert2);
1767 os_free(eap->private_key2);
1768 os_free(eap->private_key2_passwd);
1769 os_free(eap->dh_file2);
1770 os_free(eap->subject_match2);
1771 os_free(eap->altsubject_match2);
1772 os_free(eap->phase1);
1773 os_free(eap->phase2);
1774 os_free(eap->pcsc);
1775 os_free(eap->pin);
1776 os_free(eap->engine_id);
1777 os_free(eap->key_id);
1778 os_free(eap->cert_id);
1779 os_free(eap->ca_cert_id);
1780 os_free(eap->key2_id);
1781 os_free(eap->cert2_id);
1782 os_free(eap->ca_cert2_id);
1783 os_free(eap->pin2);
1784 os_free(eap->engine2_id);
1785 os_free(eap->otp);
1786 os_free(eap->pending_req_otp);
1787 os_free(eap->pac_file);
1788 os_free(eap->new_password);
1789}
1790#endif /* IEEE8021X_EAPOL */
1791
1792
1793/**
1794 * wpa_config_free_ssid - Free network/ssid configuration data
1795 * @ssid: Configuration data for the network
1796 *
1797 * This function frees all resources allocated for the network configuration
1798 * data.
1799 */
1800void wpa_config_free_ssid(struct wpa_ssid *ssid)
1801{
1802 os_free(ssid->ssid);
1803 os_free(ssid->passphrase);
1804#ifdef IEEE8021X_EAPOL
1805 eap_peer_config_free(&ssid->eap);
1806#endif /* IEEE8021X_EAPOL */
1807 os_free(ssid->id_str);
1808 os_free(ssid->scan_freq);
1809 os_free(ssid->freq_list);
1810 os_free(ssid->bgscan);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001811 os_free(ssid->p2p_client_list);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001812#ifdef CONFIG_HT_OVERRIDES
1813 os_free(ssid->ht_mcs);
1814#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001815 os_free(ssid);
1816}
1817
1818
1819/**
1820 * wpa_config_free - Free configuration data
1821 * @config: Configuration data from wpa_config_read()
1822 *
1823 * This function frees all resources allocated for the configuration data by
1824 * wpa_config_read().
1825 */
1826void wpa_config_free(struct wpa_config *config)
1827{
1828#ifndef CONFIG_NO_CONFIG_BLOBS
1829 struct wpa_config_blob *blob, *prevblob;
1830#endif /* CONFIG_NO_CONFIG_BLOBS */
1831 struct wpa_ssid *ssid, *prev = NULL;
1832
1833 ssid = config->ssid;
1834 while (ssid) {
1835 prev = ssid;
1836 ssid = ssid->next;
1837 wpa_config_free_ssid(prev);
1838 }
1839
1840#ifndef CONFIG_NO_CONFIG_BLOBS
1841 blob = config->blobs;
1842 prevblob = NULL;
1843 while (blob) {
1844 prevblob = blob;
1845 blob = blob->next;
1846 wpa_config_free_blob(prevblob);
1847 }
1848#endif /* CONFIG_NO_CONFIG_BLOBS */
1849
1850 os_free(config->ctrl_interface);
1851 os_free(config->ctrl_interface_group);
1852 os_free(config->opensc_engine_path);
1853 os_free(config->pkcs11_engine_path);
1854 os_free(config->pkcs11_module_path);
1855 os_free(config->driver_param);
1856 os_free(config->device_name);
1857 os_free(config->manufacturer);
1858 os_free(config->model_name);
1859 os_free(config->model_number);
1860 os_free(config->serial_number);
1861 os_free(config->config_methods);
1862 os_free(config->p2p_ssid_postfix);
1863 os_free(config->pssid);
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08001864 os_free(config->home_realm);
1865 os_free(config->home_username);
1866 os_free(config->home_password);
1867 os_free(config->home_ca_cert);
1868 os_free(config->home_imsi);
1869 os_free(config->home_milenage);
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08001870#ifdef ANDROID_P2P
1871 os_free(config->prioritize);
1872#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07001873 os_free(config);
1874}
1875
1876
1877/**
1878 * wpa_config_foreach_network - Iterate over each configured network
1879 * @config: Configuration data from wpa_config_read()
1880 * @func: Callback function to process each network
1881 * @arg: Opaque argument to pass to callback function
1882 *
1883 * Iterate over the set of configured networks calling the specified
1884 * function for each item. We guard against callbacks removing the
1885 * supplied network.
1886 */
1887void wpa_config_foreach_network(struct wpa_config *config,
1888 void (*func)(void *, struct wpa_ssid *),
1889 void *arg)
1890{
1891 struct wpa_ssid *ssid, *next;
1892
1893 ssid = config->ssid;
1894 while (ssid) {
1895 next = ssid->next;
1896 func(arg, ssid);
1897 ssid = next;
1898 }
1899}
1900
1901
1902/**
1903 * wpa_config_get_network - Get configured network based on id
1904 * @config: Configuration data from wpa_config_read()
1905 * @id: Unique network id to search for
1906 * Returns: Network configuration or %NULL if not found
1907 */
1908struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
1909{
1910 struct wpa_ssid *ssid;
1911
1912 ssid = config->ssid;
1913 while (ssid) {
1914 if (id == ssid->id)
1915 break;
1916 ssid = ssid->next;
1917 }
1918
1919 return ssid;
1920}
1921
1922
1923/**
1924 * wpa_config_add_network - Add a new network with empty configuration
1925 * @config: Configuration data from wpa_config_read()
1926 * Returns: The new network configuration or %NULL if operation failed
1927 */
1928struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
1929{
1930 int id;
1931 struct wpa_ssid *ssid, *last = NULL;
1932
1933 id = -1;
1934 ssid = config->ssid;
1935 while (ssid) {
1936 if (ssid->id > id)
1937 id = ssid->id;
1938 last = ssid;
1939 ssid = ssid->next;
1940 }
1941 id++;
1942
1943 ssid = os_zalloc(sizeof(*ssid));
1944 if (ssid == NULL)
1945 return NULL;
1946 ssid->id = id;
1947 if (last)
1948 last->next = ssid;
1949 else
1950 config->ssid = ssid;
1951
1952 wpa_config_update_prio_list(config);
1953
1954 return ssid;
1955}
1956
1957
1958/**
1959 * wpa_config_remove_network - Remove a configured network based on id
1960 * @config: Configuration data from wpa_config_read()
1961 * @id: Unique network id to search for
1962 * Returns: 0 on success, or -1 if the network was not found
1963 */
1964int wpa_config_remove_network(struct wpa_config *config, int id)
1965{
1966 struct wpa_ssid *ssid, *prev = NULL;
1967
1968 ssid = config->ssid;
1969 while (ssid) {
1970 if (id == ssid->id)
1971 break;
1972 prev = ssid;
1973 ssid = ssid->next;
1974 }
1975
1976 if (ssid == NULL)
1977 return -1;
1978
1979 if (prev)
1980 prev->next = ssid->next;
1981 else
1982 config->ssid = ssid->next;
1983
1984 wpa_config_update_prio_list(config);
1985 wpa_config_free_ssid(ssid);
1986 return 0;
1987}
1988
1989
1990/**
1991 * wpa_config_set_network_defaults - Set network default values
1992 * @ssid: Pointer to network configuration data
1993 */
1994void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
1995{
1996 ssid->proto = DEFAULT_PROTO;
1997 ssid->pairwise_cipher = DEFAULT_PAIRWISE;
1998 ssid->group_cipher = DEFAULT_GROUP;
1999 ssid->key_mgmt = DEFAULT_KEY_MGMT;
2000#ifdef IEEE8021X_EAPOL
2001 ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
2002 ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
2003 ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
2004#endif /* IEEE8021X_EAPOL */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002005#ifdef CONFIG_HT_OVERRIDES
2006 ssid->disable_ht = DEFAULT_DISABLE_HT;
2007 ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
2008 ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
2009 ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
2010 ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
2011#endif /* CONFIG_HT_OVERRIDES */
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002012}
2013
2014
2015/**
2016 * wpa_config_set - Set a variable in network configuration
2017 * @ssid: Pointer to network configuration data
2018 * @var: Variable name, e.g., "ssid"
2019 * @value: Variable value
2020 * @line: Line number in configuration file or 0 if not used
2021 * Returns: 0 on success, -1 on failure
2022 *
2023 * This function can be used to set network configuration variables based on
2024 * both the configuration file and management interface input. The value
2025 * parameter must be in the same format as the text-based configuration file is
2026 * using. For example, strings are using double quotation marks.
2027 */
2028int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
2029 int line)
2030{
2031 size_t i;
2032 int ret = 0;
2033
2034 if (ssid == NULL || var == NULL || value == NULL)
2035 return -1;
2036
2037 for (i = 0; i < NUM_SSID_FIELDS; i++) {
2038 const struct parse_data *field = &ssid_fields[i];
2039 if (os_strcmp(var, field->name) != 0)
2040 continue;
2041
2042 if (field->parser(field, ssid, line, value)) {
2043 if (line) {
2044 wpa_printf(MSG_ERROR, "Line %d: failed to "
2045 "parse %s '%s'.", line, var, value);
2046 }
2047 ret = -1;
2048 }
2049 break;
2050 }
2051 if (i == NUM_SSID_FIELDS) {
2052 if (line) {
2053 wpa_printf(MSG_ERROR, "Line %d: unknown network field "
2054 "'%s'.", line, var);
2055 }
2056 ret = -1;
2057 }
2058
2059 return ret;
2060}
2061
2062
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002063int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
2064 const char *value)
2065{
2066 size_t len;
2067 char *buf;
2068 int ret;
2069
2070 len = os_strlen(value);
2071 buf = os_malloc(len + 3);
2072 if (buf == NULL)
2073 return -1;
2074 buf[0] = '"';
2075 os_memcpy(buf + 1, value, len);
2076 buf[len + 1] = '"';
2077 buf[len + 2] = '\0';
2078 ret = wpa_config_set(ssid, var, buf, 0);
2079 os_free(buf);
2080 return ret;
2081}
2082
2083
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002084/**
2085 * wpa_config_get_all - Get all options from network configuration
2086 * @ssid: Pointer to network configuration data
2087 * @get_keys: Determines if keys/passwords will be included in returned list
2088 * (if they may be exported)
2089 * Returns: %NULL terminated list of all set keys and their values in the form
2090 * of [key1, val1, key2, val2, ... , NULL]
2091 *
2092 * This function can be used to get list of all configured network properties.
2093 * The caller is responsible for freeing the returned list and all its
2094 * elements.
2095 */
2096char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
2097{
2098 const struct parse_data *field;
2099 char *key, *value;
2100 size_t i;
2101 char **props;
2102 int fields_num;
2103
2104 get_keys = get_keys && ssid->export_keys;
2105
2106 props = os_zalloc(sizeof(char *) * ((2 * NUM_SSID_FIELDS) + 1));
2107 if (!props)
2108 return NULL;
2109
2110 fields_num = 0;
2111 for (i = 0; i < NUM_SSID_FIELDS; i++) {
2112 field = &ssid_fields[i];
2113 if (field->key_data && !get_keys)
2114 continue;
2115 value = field->writer(field, ssid);
2116 if (value == NULL)
2117 continue;
2118 if (os_strlen(value) == 0) {
2119 os_free(value);
2120 continue;
2121 }
2122
2123 key = os_strdup(field->name);
2124 if (key == NULL) {
2125 os_free(value);
2126 goto err;
2127 }
2128
2129 props[fields_num * 2] = key;
2130 props[fields_num * 2 + 1] = value;
2131
2132 fields_num++;
2133 }
2134
2135 return props;
2136
2137err:
2138 value = *props;
2139 while (value)
2140 os_free(value++);
2141 os_free(props);
2142 return NULL;
2143}
2144
2145
2146#ifndef NO_CONFIG_WRITE
2147/**
2148 * wpa_config_get - Get a variable in network configuration
2149 * @ssid: Pointer to network configuration data
2150 * @var: Variable name, e.g., "ssid"
2151 * Returns: Value of the variable or %NULL on failure
2152 *
2153 * This function can be used to get network configuration variables. The
2154 * returned value is a copy of the configuration variable in text format, i.e,.
2155 * the same format that the text-based configuration file and wpa_config_set()
2156 * are using for the value. The caller is responsible for freeing the returned
2157 * value.
2158 */
2159char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
2160{
2161 size_t i;
2162
2163 if (ssid == NULL || var == NULL)
2164 return NULL;
2165
2166 for (i = 0; i < NUM_SSID_FIELDS; i++) {
2167 const struct parse_data *field = &ssid_fields[i];
2168 if (os_strcmp(var, field->name) == 0)
2169 return field->writer(field, ssid);
2170 }
2171
2172 return NULL;
2173}
2174
2175
2176/**
2177 * wpa_config_get_no_key - Get a variable in network configuration (no keys)
2178 * @ssid: Pointer to network configuration data
2179 * @var: Variable name, e.g., "ssid"
2180 * Returns: Value of the variable or %NULL on failure
2181 *
2182 * This function can be used to get network configuration variable like
2183 * wpa_config_get(). The only difference is that this functions does not expose
2184 * key/password material from the configuration. In case a key/password field
2185 * is requested, the returned value is an empty string or %NULL if the variable
2186 * is not set or "*" if the variable is set (regardless of its value). The
2187 * returned value is a copy of the configuration variable in text format, i.e,.
2188 * the same format that the text-based configuration file and wpa_config_set()
2189 * are using for the value. The caller is responsible for freeing the returned
2190 * value.
2191 */
2192char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
2193{
2194 size_t i;
2195
2196 if (ssid == NULL || var == NULL)
2197 return NULL;
2198
2199 for (i = 0; i < NUM_SSID_FIELDS; i++) {
2200 const struct parse_data *field = &ssid_fields[i];
2201 if (os_strcmp(var, field->name) == 0) {
2202 char *res = field->writer(field, ssid);
2203 if (field->key_data) {
2204 if (res && res[0]) {
2205 wpa_printf(MSG_DEBUG, "Do not allow "
2206 "key_data field to be "
2207 "exposed");
2208 os_free(res);
2209 return os_strdup("*");
2210 }
2211
2212 os_free(res);
2213 return NULL;
2214 }
2215 return res;
2216 }
2217 }
2218
2219 return NULL;
2220}
2221#endif /* NO_CONFIG_WRITE */
2222
2223
2224/**
2225 * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
2226 * @ssid: Pointer to network configuration data
2227 *
2228 * This function must be called to update WPA PSK when either SSID or the
2229 * passphrase has changed for the network configuration.
2230 */
2231void wpa_config_update_psk(struct wpa_ssid *ssid)
2232{
2233#ifndef CONFIG_NO_PBKDF2
2234 pbkdf2_sha1(ssid->passphrase,
2235 (char *) ssid->ssid, ssid->ssid_len, 4096,
2236 ssid->psk, PMK_LEN);
2237 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
2238 ssid->psk, PMK_LEN);
2239 ssid->psk_set = 1;
2240#endif /* CONFIG_NO_PBKDF2 */
2241}
2242
2243
2244#ifndef CONFIG_NO_CONFIG_BLOBS
2245/**
2246 * wpa_config_get_blob - Get a named configuration blob
2247 * @config: Configuration data from wpa_config_read()
2248 * @name: Name of the blob
2249 * Returns: Pointer to blob data or %NULL if not found
2250 */
2251const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
2252 const char *name)
2253{
2254 struct wpa_config_blob *blob = config->blobs;
2255
2256 while (blob) {
2257 if (os_strcmp(blob->name, name) == 0)
2258 return blob;
2259 blob = blob->next;
2260 }
2261 return NULL;
2262}
2263
2264
2265/**
2266 * wpa_config_set_blob - Set or add a named configuration blob
2267 * @config: Configuration data from wpa_config_read()
2268 * @blob: New value for the blob
2269 *
2270 * Adds a new configuration blob or replaces the current value of an existing
2271 * blob.
2272 */
2273void wpa_config_set_blob(struct wpa_config *config,
2274 struct wpa_config_blob *blob)
2275{
2276 wpa_config_remove_blob(config, blob->name);
2277 blob->next = config->blobs;
2278 config->blobs = blob;
2279}
2280
2281
2282/**
2283 * wpa_config_free_blob - Free blob data
2284 * @blob: Pointer to blob to be freed
2285 */
2286void wpa_config_free_blob(struct wpa_config_blob *blob)
2287{
2288 if (blob) {
2289 os_free(blob->name);
2290 os_free(blob->data);
2291 os_free(blob);
2292 }
2293}
2294
2295
2296/**
2297 * wpa_config_remove_blob - Remove a named configuration blob
2298 * @config: Configuration data from wpa_config_read()
2299 * @name: Name of the blob to remove
2300 * Returns: 0 if blob was removed or -1 if blob was not found
2301 */
2302int wpa_config_remove_blob(struct wpa_config *config, const char *name)
2303{
2304 struct wpa_config_blob *pos = config->blobs, *prev = NULL;
2305
2306 while (pos) {
2307 if (os_strcmp(pos->name, name) == 0) {
2308 if (prev)
2309 prev->next = pos->next;
2310 else
2311 config->blobs = pos->next;
2312 wpa_config_free_blob(pos);
2313 return 0;
2314 }
2315 prev = pos;
2316 pos = pos->next;
2317 }
2318
2319 return -1;
2320}
2321#endif /* CONFIG_NO_CONFIG_BLOBS */
2322
2323
2324/**
2325 * wpa_config_alloc_empty - Allocate an empty configuration
2326 * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
2327 * socket
2328 * @driver_param: Driver parameters
2329 * Returns: Pointer to allocated configuration data or %NULL on failure
2330 */
2331struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
2332 const char *driver_param)
2333{
2334 struct wpa_config *config;
2335
2336 config = os_zalloc(sizeof(*config));
2337 if (config == NULL)
2338 return NULL;
2339 config->eapol_version = DEFAULT_EAPOL_VERSION;
2340 config->ap_scan = DEFAULT_AP_SCAN;
2341 config->fast_reauth = DEFAULT_FAST_REAUTH;
2342 config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
2343 config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
2344 config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
2345 config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
2346 config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
2347 config->max_num_sta = DEFAULT_MAX_NUM_STA;
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002348 config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002349
2350 if (ctrl_interface)
2351 config->ctrl_interface = os_strdup(ctrl_interface);
2352 if (driver_param)
2353 config->driver_param = os_strdup(driver_param);
2354
2355 return config;
2356}
2357
2358
2359#ifndef CONFIG_NO_STDOUT_DEBUG
2360/**
2361 * wpa_config_debug_dump_networks - Debug dump of configured networks
2362 * @config: Configuration data from wpa_config_read()
2363 */
2364void wpa_config_debug_dump_networks(struct wpa_config *config)
2365{
2366 int prio;
2367 struct wpa_ssid *ssid;
2368
2369 for (prio = 0; prio < config->num_prio; prio++) {
2370 ssid = config->pssid[prio];
2371 wpa_printf(MSG_DEBUG, "Priority group %d",
2372 ssid->priority);
2373 while (ssid) {
2374 wpa_printf(MSG_DEBUG, " id=%d ssid='%s'",
2375 ssid->id,
2376 wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
2377 ssid = ssid->pnext;
2378 }
2379 }
2380}
2381#endif /* CONFIG_NO_STDOUT_DEBUG */
2382
2383
2384struct global_parse_data {
2385 char *name;
2386 int (*parser)(const struct global_parse_data *data,
2387 struct wpa_config *config, int line, const char *value);
2388 void *param1, *param2, *param3;
2389 unsigned int changed_flag;
2390};
2391
2392
2393static int wpa_global_config_parse_int(const struct global_parse_data *data,
2394 struct wpa_config *config, int line,
2395 const char *pos)
2396{
2397 int *dst;
2398 dst = (int *) (((u8 *) config) + (long) data->param1);
2399 *dst = atoi(pos);
2400 wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
2401
2402 if (data->param2 && *dst < (long) data->param2) {
2403 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
2404 "min_value=%ld)", line, data->name, *dst,
2405 (long) data->param2);
2406 *dst = (long) data->param2;
2407 return -1;
2408 }
2409
2410 if (data->param3 && *dst > (long) data->param3) {
2411 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
2412 "max_value=%ld)", line, data->name, *dst,
2413 (long) data->param3);
2414 *dst = (long) data->param3;
2415 return -1;
2416 }
2417
2418 return 0;
2419}
2420
2421
2422static int wpa_global_config_parse_str(const struct global_parse_data *data,
2423 struct wpa_config *config, int line,
2424 const char *pos)
2425{
2426 size_t len;
2427 char **dst, *tmp;
2428
2429 len = os_strlen(pos);
2430 if (data->param2 && len < (size_t) data->param2) {
2431 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
2432 "min_len=%ld)", line, data->name,
2433 (unsigned long) len, (long) data->param2);
2434 return -1;
2435 }
2436
2437 if (data->param3 && len > (size_t) data->param3) {
2438 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
2439 "max_len=%ld)", line, data->name,
2440 (unsigned long) len, (long) data->param3);
2441 return -1;
2442 }
2443
2444 tmp = os_strdup(pos);
2445 if (tmp == NULL)
2446 return -1;
2447
2448 dst = (char **) (((u8 *) config) + (long) data->param1);
2449 os_free(*dst);
2450 *dst = tmp;
2451 wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
2452
2453 return 0;
2454}
2455
2456
2457static int wpa_config_process_country(const struct global_parse_data *data,
2458 struct wpa_config *config, int line,
2459 const char *pos)
2460{
2461 if (!pos[0] || !pos[1]) {
2462 wpa_printf(MSG_DEBUG, "Invalid country set");
2463 return -1;
2464 }
2465 config->country[0] = pos[0];
2466 config->country[1] = pos[1];
2467 wpa_printf(MSG_DEBUG, "country='%c%c'",
2468 config->country[0], config->country[1]);
2469 return 0;
2470}
2471
2472
2473static int wpa_config_process_load_dynamic_eap(
2474 const struct global_parse_data *data, struct wpa_config *config,
2475 int line, const char *so)
2476{
2477 int ret;
2478 wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
2479 ret = eap_peer_method_load(so);
2480 if (ret == -2) {
2481 wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
2482 "reloading.");
2483 } else if (ret) {
2484 wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
2485 "method '%s'.", line, so);
2486 return -1;
2487 }
2488
2489 return 0;
2490}
2491
2492
2493#ifdef CONFIG_WPS
2494
2495static int wpa_config_process_uuid(const struct global_parse_data *data,
2496 struct wpa_config *config, int line,
2497 const char *pos)
2498{
2499 char buf[40];
2500 if (uuid_str2bin(pos, config->uuid)) {
2501 wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
2502 return -1;
2503 }
2504 uuid_bin2str(config->uuid, buf, sizeof(buf));
2505 wpa_printf(MSG_DEBUG, "uuid=%s", buf);
2506 return 0;
2507}
2508
2509
2510static int wpa_config_process_device_type(
2511 const struct global_parse_data *data,
2512 struct wpa_config *config, int line, const char *pos)
2513{
2514 return wps_dev_type_str2bin(pos, config->device_type);
2515}
2516
2517
2518static int wpa_config_process_os_version(const struct global_parse_data *data,
2519 struct wpa_config *config, int line,
2520 const char *pos)
2521{
2522 if (hexstr2bin(pos, config->os_version, 4)) {
2523 wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
2524 return -1;
2525 }
2526 wpa_printf(MSG_DEBUG, "os_version=%08x",
2527 WPA_GET_BE32(config->os_version));
2528 return 0;
2529}
2530
2531#endif /* CONFIG_WPS */
2532
2533#ifdef CONFIG_P2P
2534static int wpa_config_process_sec_device_type(
2535 const struct global_parse_data *data,
2536 struct wpa_config *config, int line, const char *pos)
2537{
2538 int idx;
2539
2540 if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) {
2541 wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type "
2542 "items", line);
2543 return -1;
2544 }
2545
2546 idx = config->num_sec_device_types;
2547
2548 if (wps_dev_type_str2bin(pos, config->sec_device_type[idx]))
2549 return -1;
2550
2551 config->num_sec_device_types++;
2552 return 0;
2553}
2554#endif /* CONFIG_P2P */
2555
2556
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002557static int wpa_config_process_hessid(
2558 const struct global_parse_data *data,
2559 struct wpa_config *config, int line, const char *pos)
2560{
2561 if (hwaddr_aton2(pos, config->hessid) < 0) {
2562 wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
2563 line, pos);
2564 return -1;
2565 }
2566
2567 return 0;
2568}
2569
2570
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002571#ifdef OFFSET
2572#undef OFFSET
2573#endif /* OFFSET */
2574/* OFFSET: Get offset of a variable within the wpa_config structure */
2575#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
2576
2577#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
2578#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
2579#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f)
2580#define INT(f) _INT(f), NULL, NULL
2581#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
2582#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
2583#define STR(f) _STR(f), NULL, NULL
2584#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
2585
2586static const struct global_parse_data global_fields[] = {
2587#ifdef CONFIG_CTRL_IFACE
2588 { STR(ctrl_interface), 0 },
2589 { STR(ctrl_interface_group), 0 } /* deprecated */,
2590#endif /* CONFIG_CTRL_IFACE */
2591 { INT_RANGE(eapol_version, 1, 2), 0 },
2592 { INT(ap_scan), 0 },
2593 { INT(fast_reauth), 0 },
2594 { STR(opensc_engine_path), 0 },
2595 { STR(pkcs11_engine_path), 0 },
2596 { STR(pkcs11_module_path), 0 },
2597 { STR(driver_param), 0 },
2598 { INT(dot11RSNAConfigPMKLifetime), 0 },
2599 { INT(dot11RSNAConfigPMKReauthThreshold), 0 },
2600 { INT(dot11RSNAConfigSATimeout), 0 },
2601#ifndef CONFIG_NO_CONFIG_WRITE
2602 { INT(update_config), 0 },
2603#endif /* CONFIG_NO_CONFIG_WRITE */
2604 { FUNC_NO_VAR(load_dynamic_eap), 0 },
2605#ifdef CONFIG_WPS
2606 { FUNC(uuid), CFG_CHANGED_UUID },
2607 { STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME },
2608 { STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
2609 { STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
2610 { STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
2611 { STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING },
2612 { FUNC(device_type), CFG_CHANGED_DEVICE_TYPE },
2613 { FUNC(os_version), CFG_CHANGED_OS_VERSION },
2614 { STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
2615 { INT_RANGE(wps_cred_processing, 0, 2), 0 },
2616#endif /* CONFIG_WPS */
2617#ifdef CONFIG_P2P
2618 { FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
2619 { INT(p2p_listen_reg_class), 0 },
2620 { INT(p2p_listen_channel), 0 },
2621 { INT(p2p_oper_reg_class), 0 },
2622 { INT(p2p_oper_channel), 0 },
2623 { INT_RANGE(p2p_go_intent, 0, 15), 0 },
2624 { STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
2625 { INT_RANGE(persistent_reconnect, 0, 1), 0 },
2626 { INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
2627 { INT(p2p_group_idle), 0 },
2628#endif /* CONFIG_P2P */
Dmitry Shmidtc5ec7f52012-03-06 16:33:24 -08002629#ifdef ANDROID_P2P
2630 { STR_RANGE(prioritize, 0, 32), CFG_CHANGED_IFACE_PRIORITY },
2631#endif
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002632 { FUNC(country), CFG_CHANGED_COUNTRY },
2633 { INT(bss_max_count), 0 },
2634 { INT(bss_expiration_age), 0 },
2635 { INT(bss_expiration_scan_count), 0 },
2636 { INT_RANGE(filter_ssids, 0, 1), 0 },
2637 { INT(max_num_sta), 0 },
Dmitry Shmidt1f69aa52012-01-24 16:10:04 -08002638 { INT_RANGE(disassoc_low_ack, 0, 1), 0 },
2639 { STR(home_realm), 0 },
2640 { STR(home_username), 0 },
2641 { STR(home_password), 0 },
2642 { STR(home_ca_cert), 0 },
2643 { STR(home_imsi), 0 },
2644 { STR(home_milenage), 0 },
2645 { INT_RANGE(interworking, 0, 1), 0 },
2646 { FUNC(hessid), 0 },
2647 { INT_RANGE(access_network_type, 0, 15), 0 }
Dmitry Shmidt8d520ff2011-05-09 14:06:53 -07002648};
2649
2650#undef FUNC
2651#undef _INT
2652#undef INT
2653#undef INT_RANGE
2654#undef _STR
2655#undef STR
2656#undef STR_RANGE
2657#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
2658
2659
2660int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
2661{
2662 size_t i;
2663 int ret = 0;
2664
2665 for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
2666 const struct global_parse_data *field = &global_fields[i];
2667 size_t flen = os_strlen(field->name);
2668 if (os_strncmp(pos, field->name, flen) != 0 ||
2669 pos[flen] != '=')
2670 continue;
2671
2672 if (field->parser(field, config, line, pos + flen + 1)) {
2673 wpa_printf(MSG_ERROR, "Line %d: failed to "
2674 "parse '%s'.", line, pos);
2675 ret = -1;
2676 }
2677 config->changed_parameters |= field->changed_flag;
2678 break;
2679 }
2680 if (i == NUM_GLOBAL_FIELDS) {
2681 if (line < 0)
2682 return -1;
2683 wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
2684 line, pos);
2685 ret = -1;
2686 }
2687
2688 return ret;
2689}