]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/wpa_supplicant/config.c
This commit was generated by cvs2svn to compensate for changes in r147455,
[FreeBSD/FreeBSD.git] / contrib / wpa_supplicant / config.c
1 /*
2  * WPA Supplicant / Configuration file parser
3  * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.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 <stdlib.h>
16 #include <stdio.h>
17 #include <string.h>
18
19 #include "common.h"
20 #include "wpa.h"
21 #include "config.h"
22 #include "sha1.h"
23 #include "wpa_supplicant.h"
24 #include "eapol_sm.h"
25 #include "eap.h"
26 #include "config.h"
27
28
29 struct parse_data {
30         char *name;
31         int (*parser)(struct parse_data *data, int line, const char *value);
32         void *param1, *param2, *param3, *param4;
33         struct wpa_ssid *ssid;
34         int key_data;
35 };
36
37
38 static char * wpa_config_get_line(char *s, int size, FILE *stream, int *line)
39 {
40         char *pos, *end, *sstart;
41
42         while (fgets(s, size, stream)) {
43                 (*line)++;
44                 s[size - 1] = '\0';
45                 pos = s;
46
47                 while (*pos == ' ' || *pos == '\t' || *pos == '\r')
48                         pos++;
49                 if (*pos == '#' || *pos == '\n' || *pos == '\0' ||
50                     *pos == '\r')
51                         continue;
52
53                 /* Remove # comments unless they are within a double quoted
54                  * string. Remove trailing white space. */
55                 sstart = strchr(pos, '"');
56                 if (sstart)
57                         sstart = strchr(sstart + 1, '"');
58                 if (!sstart)
59                         sstart = pos;
60                 end = strchr(sstart, '#');
61                 if (end)
62                         *end-- = '\0';
63                 else
64                         end = pos + strlen(pos) - 1;
65                 while (end > pos &&
66                        (*end == '\n' || *end == ' ' || *end == '\t' ||
67                         *end == '\r')) {
68                         *end-- = '\0';
69                 }
70                 if (*pos == '\0')
71                         continue;
72
73                 return pos;
74         }
75
76         return NULL;
77 }
78
79
80 static char * wpa_config_parse_string(const char *value, size_t *len)
81 {
82         if (*value == '"') {
83                 char *pos;
84                 value++;
85                 pos = strchr(value, '"');
86                 if (pos == NULL || pos[1] != '\0')
87                         return NULL;
88                 *pos = '\0';
89                 *len = strlen(value);
90                 return strdup(value);
91         } else {
92                 u8 *str;
93                 int hlen = strlen(value);
94                 if (hlen % 1)
95                         return NULL;
96                 *len = hlen / 2;
97                 str = malloc(*len);
98                 if (str == NULL)
99                         return NULL;
100                 if (hexstr2bin(value, str, *len)) {
101                         free(str);
102                         return NULL;
103                 }
104                 return (char *) str;
105         }
106 }
107
108
109 static int wpa_config_parse_str(struct parse_data *data,
110                                 int line, const char *value)
111 {
112         size_t res_len, *dst_len;
113         char **dst;
114
115         dst = (char **) (((u8 *) data->ssid) + (long) data->param1);
116         dst_len = (size_t *) (((u8 *) data->ssid) + (long) data->param2);
117
118         free(*dst);
119         *dst = wpa_config_parse_string(value, &res_len);
120         if (*dst == NULL) {
121                 wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
122                            line, data->name, value);
123                 return -1;
124         }
125         if (data->param2)
126                 *dst_len = res_len;
127
128         if (data->key_data) {
129                 wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
130                                       (u8 *) *dst, res_len);
131         } else {
132                 wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
133                                   (u8 *) *dst, res_len);
134         }
135
136         if (data->param3 && res_len < (size_t) data->param3) {
137                 wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
138                            "min_len=%ld)", line, data->name,
139                            (unsigned long) res_len, (long) data->param3);
140                 free(*dst);
141                 *dst = NULL;
142                 return -1;
143         }
144
145         if (data->param4 && res_len > (size_t) data->param4) {
146                 wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
147                            "max_len=%ld)", line, data->name,
148                            (unsigned long) res_len, (long) data->param4);
149                 free(*dst);
150                 *dst = NULL;
151                 return -1;
152         }
153
154         return 0;
155 }
156
157
158 static int wpa_config_parse_int(struct parse_data *data,
159                                 int line, const char *value)
160 {
161         int *dst;
162
163         dst = (int *) (((u8 *) data->ssid) + (long) data->param1);
164         *dst = atoi(value);
165         wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
166
167         if (data->param3 && *dst < (long) data->param3) {
168                 wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
169                            "min_value=%ld)", line, data->name, *dst,
170                            (long) data->param3);
171                 *dst = (long) data->param3;
172                 return -1;
173         }
174
175         if (data->param4 && *dst > (long) data->param4) {
176                 wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
177                            "max_value=%ld)", line, data->name, *dst,
178                            (long) data->param4);
179                 *dst = (long) data->param4;
180                 return -1;
181         }
182
183         return 0;
184 }
185
186
187 static int wpa_config_parse_bssid(struct parse_data *data, int line,
188                                   const char *value)
189 {
190         if (hwaddr_aton(value, data->ssid->bssid)) {
191                 wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
192                            line, value);
193                 return -1;
194         }
195         data->ssid->bssid_set = 1;
196         wpa_hexdump(MSG_MSGDUMP, "BSSID", data->ssid->bssid, ETH_ALEN);
197         return 0;
198 }
199
200
201 static int wpa_config_parse_psk(struct parse_data *data, int line,
202                                 const char *value)
203 {
204         if (*value == '"') {
205                 char *pos;
206                 int len;
207
208                 value++;
209                 pos = strrchr(value, '"');
210                 if (pos)
211                         *pos = '\0';
212                 len = strlen(value);
213                 if (len < 8 || len > 63) {
214                         wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
215                                    "length %d (expected: 8..63) '%s'.",
216                                    line, len, value);
217                         return -1;
218                 }
219                 wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
220                                       (u8 *) value, len);
221                 data->ssid->passphrase = strdup(value);
222                 return data->ssid->passphrase == NULL ? -1 : 0;
223         }
224
225         if (hexstr2bin(value, data->ssid->psk, PMK_LEN) ||
226             value[PMK_LEN * 2] != '\0') {
227                 wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
228                            line, value);
229                 return -1;
230         }
231         data->ssid->psk_set = 1;
232         wpa_hexdump_key(MSG_MSGDUMP, "PSK", data->ssid->psk, PMK_LEN);
233         return 0;
234 }
235
236
237 static int wpa_config_parse_proto(struct parse_data *data, int line,
238                                   const char *value)
239 {
240         int val = 0, last, errors = 0;
241         char *start, *end, *buf;
242
243         buf = strdup(value);
244         if (buf == NULL)
245                 return -1;
246         start = buf;
247
248         while (*start != '\0') {
249                 while (*start == ' ' || *start == '\t')
250                         start++;
251                 if (*start == '\0')
252                         break;
253                 end = start;
254                 while (*end != ' ' && *end != '\t' && *end != '\0')
255                         end++;
256                 last = *end == '\0';
257                 *end = '\0';
258                 if (strcmp(start, "WPA") == 0)
259                         val |= WPA_PROTO_WPA;
260                 else if (strcmp(start, "RSN") == 0 ||
261                          strcmp(start, "WPA2") == 0)
262                         val |= WPA_PROTO_RSN;
263                 else {
264                         wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
265                                    line, start);
266                         errors++;
267                 }
268
269                 if (last)
270                         break;
271                 start = end + 1;
272         }
273         free(buf);
274
275         if (val == 0) {
276                 wpa_printf(MSG_ERROR,
277                            "Line %d: no proto values configured.", line);
278                 errors++;
279         }
280
281         wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
282         data->ssid->proto = val;
283         return errors ? -1 : 0;
284 }
285
286
287 static int wpa_config_parse_key_mgmt(struct parse_data *data, int line,
288                                      const char *value)
289 {
290         int val = 0, last, errors = 0;
291         char *start, *end, *buf;
292
293         buf = strdup(value);
294         if (buf == NULL)
295                 return -1;
296         start = buf;
297
298         while (*start != '\0') {
299                 while (*start == ' ' || *start == '\t')
300                         start++;
301                 if (*start == '\0')
302                         break;
303                 end = start;
304                 while (*end != ' ' && *end != '\t' && *end != '\0')
305                         end++;
306                 last = *end == '\0';
307                 *end = '\0';
308                 if (strcmp(start, "WPA-PSK") == 0)
309                         val |= WPA_KEY_MGMT_PSK;
310                 else if (strcmp(start, "WPA-EAP") == 0)
311                         val |= WPA_KEY_MGMT_IEEE8021X;
312                 else if (strcmp(start, "IEEE8021X") == 0)
313                         val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
314                 else if (strcmp(start, "NONE") == 0)
315                         val |= WPA_KEY_MGMT_NONE;
316                 else if (strcmp(start, "WPA-NONE") == 0)
317                         val |= WPA_KEY_MGMT_WPA_NONE;
318                 else {
319                         wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
320                                    line, start);
321                         errors++;
322                 }
323
324                 if (last)
325                         break;
326                 start = end + 1;
327         }
328         free(buf);
329
330         if (val == 0) {
331                 wpa_printf(MSG_ERROR,
332                            "Line %d: no key_mgmt values configured.", line);
333                 errors++;
334         }
335
336         wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
337         data->ssid->key_mgmt = val;
338         return errors ? -1 : 0;
339 }
340
341
342 static int wpa_config_parse_cipher(int line, const char *value)
343 {
344         int val = 0, last;
345         char *start, *end, *buf;
346
347         buf = strdup(value);
348         if (buf == NULL)
349                 return -1;
350         start = buf;
351
352         while (*start != '\0') {
353                 while (*start == ' ' || *start == '\t')
354                         start++;
355                 if (*start == '\0')
356                         break;
357                 end = start;
358                 while (*end != ' ' && *end != '\t' && *end != '\0')
359                         end++;
360                 last = *end == '\0';
361                 *end = '\0';
362                 if (strcmp(start, "CCMP") == 0)
363                         val |= WPA_CIPHER_CCMP;
364                 else if (strcmp(start, "TKIP") == 0)
365                         val |= WPA_CIPHER_TKIP;
366                 else if (strcmp(start, "WEP104") == 0)
367                         val |= WPA_CIPHER_WEP104;
368                 else if (strcmp(start, "WEP40") == 0)
369                         val |= WPA_CIPHER_WEP40;
370                 else if (strcmp(start, "NONE") == 0)
371                         val |= WPA_CIPHER_NONE;
372                 else {
373                         wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
374                                    line, start);
375                         free(buf);
376                         return -1;
377                 }
378
379                 if (last)
380                         break;
381                 start = end + 1;
382         }
383         free(buf);
384
385         if (val == 0) {
386                 wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
387                            line);
388                 return -1;
389         }
390         return val;
391 }
392
393
394 static int wpa_config_parse_pairwise(struct parse_data *data, int line,
395                                      const char *value)
396 {
397         int val;
398         val = wpa_config_parse_cipher(line, value);
399         if (val == -1)
400                 return -1;
401         if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_NONE)) {
402                 wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
403                            "(0x%x).", line, val);
404                 return -1;
405         }
406
407         wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
408         data->ssid->pairwise_cipher = val;
409         return 0;
410 }
411
412
413 static int wpa_config_parse_group(struct parse_data *data, int line,
414                                   const char *value)
415 {
416         int val;
417         val = wpa_config_parse_cipher(line, value);
418         if (val == -1)
419                 return -1;
420         if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | WPA_CIPHER_WEP104 |
421                     WPA_CIPHER_WEP40)) {
422                 wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
423                            "(0x%x).", line, val);
424                 return -1;
425         }
426
427         wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
428         data->ssid->group_cipher = val;
429         return 0;
430 }
431
432
433 static int wpa_config_parse_auth_alg(struct parse_data *data, int line,
434                                      const char *value)
435 {
436         int val = 0, last, errors = 0;
437         char *start, *end, *buf;
438
439         buf = strdup(value);
440         if (buf == NULL)
441                 return -1;
442         start = buf;
443
444         while (*start != '\0') {
445                 while (*start == ' ' || *start == '\t')
446                         start++;
447                 if (*start == '\0')
448                         break;
449                 end = start;
450                 while (*end != ' ' && *end != '\t' && *end != '\0')
451                         end++;
452                 last = *end == '\0';
453                 *end = '\0';
454                 if (strcmp(start, "OPEN") == 0)
455                         val |= WPA_AUTH_ALG_OPEN;
456                 else if (strcmp(start, "SHARED") == 0)
457                         val |= WPA_AUTH_ALG_SHARED;
458                 else if (strcmp(start, "LEAP") == 0)
459                         val |= WPA_AUTH_ALG_LEAP;
460                 else {
461                         wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
462                                    line, start);
463                         errors++;
464                 }
465
466                 if (last)
467                         break;
468                 start = end + 1;
469         }
470         free(buf);
471
472         if (val == 0) {
473                 wpa_printf(MSG_ERROR,
474                            "Line %d: no auth_alg values configured.", line);
475                 errors++;
476         }
477
478         wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
479         data->ssid->auth_alg = val;
480         return errors ? -1 : 0;
481 }
482
483
484 static int wpa_config_parse_eap(struct parse_data *data, int line,
485                                 const char *value)
486 {
487         int last, errors = 0;
488         char *start, *end, *buf;
489         u8 *methods = NULL, *tmp;
490         size_t num_methods = 0;
491
492         buf = strdup(value);
493         if (buf == NULL)
494                 return -1;
495         start = buf;
496
497         while (*start != '\0') {
498                 while (*start == ' ' || *start == '\t')
499                         start++;
500                 if (*start == '\0')
501                         break;
502                 end = start;
503                 while (*end != ' ' && *end != '\t' && *end != '\0')
504                         end++;
505                 last = *end == '\0';
506                 *end = '\0';
507                 tmp = methods;
508                 methods = realloc(methods, num_methods + 1);
509                 if (methods == NULL) {
510                         free(tmp);
511                         return -1;
512                 }
513                 methods[num_methods] = eap_get_type(start);
514                 if (methods[num_methods] == EAP_TYPE_NONE) {
515                         wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
516                                    "'%s'", line, start);
517                         wpa_printf(MSG_ERROR, "You may need to add support for"
518                                    " this EAP method during wpa_supplicant\n"
519                                    "build time configuration.\n"
520                                    "See README for more information.");
521                         errors++;
522                 } else if (methods[num_methods] == EAP_TYPE_LEAP)
523                         data->ssid->leap++;
524                 else
525                         data->ssid->non_leap++;
526                 num_methods++;
527                 if (last)
528                         break;
529                 start = end + 1;
530         }
531         free(buf);
532
533         tmp = methods;
534         methods = realloc(methods, num_methods + 1);
535         if (methods == NULL) {
536                 free(tmp);
537                 return -1;
538         }
539         methods[num_methods] = EAP_TYPE_NONE;
540         num_methods++;
541
542         wpa_hexdump(MSG_MSGDUMP, "eap methods", methods, num_methods);
543         data->ssid->eap_methods = methods;
544         return errors ? -1 : 0;
545 }
546
547
548 static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
549                                     const char *value, int idx)
550 {
551         char *buf, title[20];
552
553         buf = wpa_config_parse_string(value, len);
554         if (buf == NULL) {
555                 wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
556                            line, idx, value);
557                 return -1;
558         }
559         if (*len > MAX_WEP_KEY_LEN) {
560                 wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
561                            line, idx, value);
562                 free(buf);
563                 return -1;
564         }
565         memcpy(key, buf, *len);
566         free(buf);
567         snprintf(title, sizeof(title), "wep_key%d", idx);
568         wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
569         return 0;
570 }
571
572
573 static int wpa_config_parse_wep_key0(struct parse_data *data, int line,
574                                      const char *value)
575 {
576         return wpa_config_parse_wep_key(data->ssid->wep_key[0],
577                                         &data->ssid->wep_key_len[0], line,
578                                         value, 0);
579 }
580
581
582 static int wpa_config_parse_wep_key1(struct parse_data *data, int line,
583                                      const char *value)
584 {
585         return wpa_config_parse_wep_key(data->ssid->wep_key[1],
586                                         &data->ssid->wep_key_len[1], line,
587                                         value, 1);
588 }
589
590
591 static int wpa_config_parse_wep_key2(struct parse_data *data, int line,
592                                      const char *value)
593 {
594         return wpa_config_parse_wep_key(data->ssid->wep_key[2],
595                                         &data->ssid->wep_key_len[2], line,
596                                         value, 2);
597 }
598
599
600 static int wpa_config_parse_wep_key3(struct parse_data *data, int line,
601                                      const char *value)
602 {
603         return wpa_config_parse_wep_key(data->ssid->wep_key[3],
604                                         &data->ssid->wep_key_len[3], line,
605                                         value, 3);
606 }
607
608
609 #define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
610 #define STR(f) .name = #f, .parser = wpa_config_parse_str, .param1 = OFFSET(f)
611 #define STR_LEN(f) STR(f), .param2 = OFFSET(f ## _len)
612 #define STR_RANGE(f, min, max) STR_LEN(f), .param3 = (void *) (min), \
613         .param4 = (void *) (max)
614 #define INT(f) .name = #f, .parser = wpa_config_parse_int, \
615         .param1 = OFFSET(f), .param2 = (void *) 0
616 #define INT_RANGE(f, min, max) INT(f), .param3 = (void *) (min), \
617         .param4 = (void *) (max)
618 #define FUNC(f) .name = #f, .parser = wpa_config_parse_ ## f
619
620 static struct parse_data ssid_fields[] = {
621         { STR_RANGE(ssid, 0, MAX_SSID_LEN) },
622         { INT_RANGE(scan_ssid, 0, 1) },
623         { FUNC(bssid) },
624         { FUNC(psk), .key_data = 1 },
625         { FUNC(proto) },
626         { FUNC(key_mgmt) },
627         { FUNC(pairwise) },
628         { FUNC(group) },
629         { FUNC(auth_alg) },
630         { FUNC(eap) },
631         { STR_LEN(identity) },
632         { STR_LEN(anonymous_identity) },
633         { STR_RANGE(eappsk, EAP_PSK_LEN, EAP_PSK_LEN), .key_data = 1 },
634         { STR_LEN(nai) },
635         { STR_LEN(server_nai) },
636         { STR_LEN(password), .key_data = 1 },
637         { STR(ca_cert) },
638         { STR(client_cert) },
639         { STR(private_key) },
640         { STR(private_key_passwd), .key_data = 1 },
641         { STR(dh_file) },
642         { STR(subject_match) },
643         { STR(ca_cert2) },
644         { STR(client_cert2) },
645         { STR(private_key2) },
646         { STR(private_key2_passwd), .key_data = 1 },
647         { STR(dh_file2) },
648         { STR(subject_match2) },
649         { STR(phase1) },
650         { STR(phase2) },
651         { STR(pcsc) },
652         { STR(pin), .key_data = 1 },
653         { INT(eapol_flags) },
654         { FUNC(wep_key0), .key_data = 1 },
655         { FUNC(wep_key1), .key_data = 1 },
656         { FUNC(wep_key2), .key_data = 1 },
657         { FUNC(wep_key3), .key_data = 1 },
658         { INT(wep_tx_keyidx) },
659         { INT(priority) },
660         { INT(eap_workaround) },
661         { STR(pac_file) },
662         { INT_RANGE(mode, 0, 1) },
663 };
664
665 #undef OFFSET
666 #undef STR
667 #undef STR_LEN
668 #undef STR_RANGE
669 #undef INT
670 #undef INT_RANGE
671 #undef FUNC
672 #define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
673
674
675 static struct wpa_ssid * wpa_config_read_network(FILE *f, int *line, int id)
676 {
677         struct wpa_ssid *ssid;
678         int errors = 0, i, end = 0;
679         char buf[256], *pos, *pos2;
680
681         wpa_printf(MSG_MSGDUMP, "Line: %d - start of a new network block",
682                    *line);
683         ssid = (struct wpa_ssid *) malloc(sizeof(*ssid));
684         if (ssid == NULL)
685                 return NULL;
686         memset(ssid, 0, sizeof(*ssid));
687         ssid->id = id;
688
689         ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
690         ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
691         ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
692                 WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
693         ssid->key_mgmt = WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X;
694         ssid->eapol_flags = EAPOL_FLAG_REQUIRE_KEY_UNICAST |
695                 EAPOL_FLAG_REQUIRE_KEY_BROADCAST;
696         ssid->eap_workaround = (unsigned int) -1;
697
698         while ((pos = wpa_config_get_line(buf, sizeof(buf), f, line))) {
699                 if (strcmp(pos, "}") == 0) {
700                         end = 1;
701                         break;
702                 }
703
704                 pos2 = strchr(pos, '=');
705                 if (pos2 == NULL) {
706                         wpa_printf(MSG_ERROR, "Line %d: Invalid SSID line "
707                                    "'%s'.", *line, pos);
708                         errors++;
709                         continue;
710                 }
711
712                 *pos2++ = '\0';
713                 if (*pos2 == '"') {
714                         if (strchr(pos2 + 1, '"') == NULL) {
715                                 wpa_printf(MSG_ERROR, "Line %d: invalid "
716                                            "quotation '%s'.", *line, pos2);
717                                 errors++;
718                                 continue;
719                         }
720                 }
721
722                 for (i = 0; i < NUM_SSID_FIELDS; i++) {
723                         struct parse_data *field = &ssid_fields[i];
724                         if (strcmp(pos, field->name) != 0)
725                                 continue;
726
727                         field->ssid = ssid;
728                         if (field->parser(field, *line, pos2)) {
729                                 wpa_printf(MSG_ERROR, "Line %d: failed to "
730                                            "parse %s '%s'.", *line, pos, pos2);
731                                 errors++;
732                         }
733                         break;
734                 }
735                 if (i == NUM_SSID_FIELDS) {
736                         wpa_printf(MSG_ERROR, "Line %d: unknown network field "
737                                    "'%s'.", *line, pos);
738                         errors++;
739                 }
740         }
741
742         if (!end) {
743                 wpa_printf(MSG_ERROR, "Line %d: network block was not "
744                            "terminated properly.", *line);
745                 errors++;
746         }
747
748         if (ssid->passphrase) {
749                 if (ssid->psk_set) {
750                         wpa_printf(MSG_ERROR, "Line %d: both PSK and "
751                                    "passphrase configured.", *line);
752                         errors++;
753                 }
754                 pbkdf2_sha1(ssid->passphrase,
755                             (char *) ssid->ssid, ssid->ssid_len, 4096,
756                             ssid->psk, PMK_LEN);
757                 wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
758                                 ssid->psk, PMK_LEN);
759                 ssid->psk_set = 1;
760         }
761
762         if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
763                 wpa_printf(MSG_ERROR, "Line %d: WPA-PSK accepted for key "
764                            "management, but no PSK configured.", *line);
765                 errors++;
766         }
767
768         if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
769             !(ssid->pairwise_cipher & WPA_CIPHER_CCMP)) {
770                 /* Group cipher cannot be stronger than the pairwise cipher. */
771                 wpa_printf(MSG_DEBUG, "Line %d: removed CCMP from group cipher"
772                            " list since it was not allowed for pairwise "
773                            "cipher", *line);
774                 ssid->group_cipher &= ~WPA_CIPHER_CCMP;
775         }
776
777         if (errors) {
778                 free(ssid);
779                 ssid = NULL;
780         }
781
782         return ssid;
783 }
784
785
786 static int wpa_config_add_prio_network(struct wpa_config *config,
787                                        struct wpa_ssid *ssid)
788 {
789         int prio;
790         struct wpa_ssid *prev, **nlist;
791
792         for (prio = 0; prio < config->num_prio; prio++) {
793                 prev = config->pssid[prio];
794                 if (prev->priority == ssid->priority) {
795                         while (prev->pnext)
796                                 prev = prev->pnext;
797                         prev->pnext = ssid;
798                         return 0;
799                 }
800         }
801
802         /* First network for this priority - add new priority list */
803         nlist = realloc(config->pssid,
804                         (config->num_prio + 1) * sizeof(struct wpa_ssid *));
805         if (nlist == NULL)
806                 return -1;
807
808         for (prio = 0; prio < config->num_prio; prio++) {
809                 if (nlist[prio]->priority < ssid->priority)
810                         break;
811         }
812
813         memmove(&nlist[prio + 1], &nlist[prio],
814                 (config->num_prio - prio) * sizeof(struct wpa_ssid *));
815
816         nlist[prio] = ssid;
817         config->num_prio++;
818         config->pssid = nlist;
819
820         return 0;
821 }
822
823
824 struct wpa_config * wpa_config_read(const char *config_file)
825 {
826         FILE *f;
827         char buf[256], *pos;
828         int errors = 0, line = 0;
829         struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
830         struct wpa_config *config;
831         int id = 0, prio;
832
833         config = malloc(sizeof(*config));
834         if (config == NULL)
835                 return NULL;
836         memset(config, 0, sizeof(*config));
837         config->eapol_version = 1;
838         config->ap_scan = 1;
839         config->fast_reauth = 1;
840         wpa_printf(MSG_DEBUG, "Reading configuration file '%s'",
841                    config_file);
842         f = fopen(config_file, "r");
843         if (f == NULL) {
844                 free(config);
845                 return NULL;
846         }
847
848         while ((pos = wpa_config_get_line(buf, sizeof(buf), f, &line))) {
849                 if (strcmp(pos, "network={") == 0) {
850                         ssid = wpa_config_read_network(f, &line, id++);
851                         if (ssid == NULL) {
852                                 wpa_printf(MSG_ERROR, "Line %d: failed to "
853                                            "parse network block.", line);
854                                 errors++;
855                                 continue;
856                         }
857                         if (head == NULL) {
858                                 head = tail = ssid;
859                         } else {
860                                 tail->next = ssid;
861                                 tail = ssid;
862                         }
863                         if (wpa_config_add_prio_network(config, ssid)) {
864                                 wpa_printf(MSG_ERROR, "Line %d: failed to add "
865                                            "network block to priority list.",
866                                            line);
867                                 errors++;
868                                 continue;
869                         }
870 #ifdef CONFIG_CTRL_IFACE
871                 } else if (strncmp(pos, "ctrl_interface=", 15) == 0) {
872                         free(config->ctrl_interface);
873                         config->ctrl_interface = strdup(pos + 15);
874                         wpa_printf(MSG_DEBUG, "ctrl_interface='%s'",
875                                    config->ctrl_interface);
876 #ifndef CONFIG_CTRL_IFACE_UDP
877                 } else if (strncmp(pos, "ctrl_interface_group=", 21) == 0) {
878                         struct group *grp;
879                         char *endp;
880                         const char *group = pos + 21;
881
882                         grp = getgrnam(group);
883                         if (grp) {
884                                 config->ctrl_interface_gid = grp->gr_gid;
885                                 config->ctrl_interface_gid_set = 1;
886                                 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
887                                            " (from group name '%s')",
888                                            (int) config->ctrl_interface_gid, 
889                                            group);
890                                 continue;
891                         }
892
893                         /* Group name not found - try to parse this as gid */
894                         config->ctrl_interface_gid = strtol(group, &endp, 10);
895                         if (*group == '\0' || *endp != '\0') {
896                                 wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
897                                            "'%s'", line, group);
898                                 errors++;
899                                 continue;
900                         }
901                         wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
902                                    (int) config->ctrl_interface_gid);
903 #endif /* CONFIG_CTRL_IFACE_UDP */
904 #endif /* CONFIG_CTRL_IFACE */
905                 } else if (strncmp(pos, "eapol_version=", 14) == 0) {
906                         config->eapol_version = atoi(pos + 14);
907                         if (config->eapol_version < 1 ||
908                             config->eapol_version > 2) {
909                                 wpa_printf(MSG_ERROR, "Line %d: Invalid EAPOL "
910                                            "version (%d): '%s'.",
911                                            line, config->eapol_version, pos);
912                                 errors++;
913                                 continue;
914                         }
915                         wpa_printf(MSG_DEBUG, "eapol_version=%d",
916                                    config->eapol_version);
917                 } else if (strncmp(pos, "ap_scan=", 8) == 0) {
918                         config->ap_scan = atoi(pos + 8);
919                         wpa_printf(MSG_DEBUG, "ap_scan=%d", config->ap_scan);
920                 } else if (strncmp(pos, "fast_reauth=", 12) == 0) {
921                         config->fast_reauth = atoi(pos + 12);
922                         wpa_printf(MSG_DEBUG, "fast_reauth=%d",
923                                    config->fast_reauth);
924                 } else {
925                         wpa_printf(MSG_ERROR, "Line %d: Invalid configuration "
926                                    "line '%s'.", line, pos);
927                         errors++;
928                         continue;
929                 }
930         }
931
932         fclose(f);
933
934         config->ssid = head;
935         for (prio = 0; prio < config->num_prio; prio++) {
936                 ssid = config->pssid[prio];
937                 wpa_printf(MSG_DEBUG, "Priority group %d",
938                            ssid->priority);
939                 while (ssid) {
940                         wpa_printf(MSG_DEBUG, "   id=%d ssid='%s'",
941                                    ssid->id,
942                                    wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
943                         ssid = ssid->pnext;
944                 }
945         }
946         if (errors) {
947                 wpa_config_free(config);
948                 config = NULL;
949                 head = NULL;
950         }
951
952         return config;
953 }
954
955
956 void wpa_config_free(struct wpa_config *config)
957 {
958         struct wpa_ssid *ssid, *prev = NULL;
959         ssid = config->ssid;
960         while (ssid) {
961                 prev = ssid;
962                 ssid = ssid->next;
963                 free(prev->ssid);
964                 free(prev->passphrase);
965                 free(prev->eap_methods);
966                 free(prev->identity);
967                 free(prev->anonymous_identity);
968                 free(prev->eappsk);
969                 free(prev->nai);
970                 free(prev->server_nai);
971                 free(prev->password);
972                 free(prev->ca_cert);
973                 free(prev->client_cert);
974                 free(prev->private_key);
975                 free(prev->private_key_passwd);
976                 free(prev->dh_file);
977                 free(prev->subject_match);
978                 free(prev->ca_cert2);
979                 free(prev->client_cert2);
980                 free(prev->private_key2);
981                 free(prev->private_key2_passwd);
982                 free(prev->dh_file2);
983                 free(prev->subject_match2);
984                 free(prev->phase1);
985                 free(prev->phase2);
986                 free(prev->pcsc);
987                 free(prev->pin);
988                 free(prev->otp);
989                 free(prev->pending_req_otp);
990                 free(prev->pac_file);
991                 free(prev);
992         }
993         free(config->ctrl_interface);
994         free(config->pssid);
995         free(config);
996 }
997
998
999 int wpa_config_allowed_eap_method(struct wpa_ssid *ssid, int method)
1000 {
1001         u8 *pos;
1002
1003         if (ssid == NULL || ssid->eap_methods == NULL)
1004                 return 1;
1005
1006         pos = ssid->eap_methods;
1007         while (*pos != EAP_TYPE_NONE) {
1008                 if (*pos == method)
1009                         return 1;
1010                 pos++;
1011         }
1012         return 0;
1013 }
1014
1015
1016 const char * wpa_cipher_txt(int cipher)
1017 {
1018         switch (cipher) {
1019         case WPA_CIPHER_NONE:
1020                 return "NONE";
1021         case WPA_CIPHER_WEP40:
1022                 return "WEP-40";
1023         case WPA_CIPHER_WEP104:
1024                 return "WEP-104";
1025         case WPA_CIPHER_TKIP:
1026                 return "TKIP";
1027         case WPA_CIPHER_CCMP:
1028                 return "CCMP";
1029         default:
1030                 return "UNKNOWN";
1031         }
1032 }
1033
1034
1035 const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
1036 {
1037         switch (key_mgmt) {
1038         case WPA_KEY_MGMT_IEEE8021X:
1039                 return proto == WPA_PROTO_RSN ?
1040                         "WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
1041         case WPA_KEY_MGMT_PSK:
1042                 return proto == WPA_PROTO_RSN ?
1043                         "WPA2-PSK" : "WPA-PSK";
1044         case WPA_KEY_MGMT_NONE:
1045                 return "NONE";
1046         case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
1047                 return "IEEE 802.1X (no WPA)";
1048         default:
1049                 return "UNKNOWN";
1050         }
1051 }