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