Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / contrib / hostapd-0.4.9 / config.c
1 /*
2  * Host AP (software wireless LAN access point) user space daemon for
3  * Host AP kernel driver / Configuration file
4  * Copyright (c) 2003-2006, Jouni Malinen <jkmaline@cc.hut.fi>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * Alternatively, this software may be distributed under the terms of BSD
11  * license.
12  *
13  * See README and COPYING for more details.
14  */
15
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <unistd.h>
19 #include <netinet/in.h>
20 #include <string.h>
21 #include <sys/socket.h>
22 #include <sys/socket.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 #include <grp.h>
26
27 #include "hostapd.h"
28 #include "driver.h"
29 #include "sha1.h"
30 #include "eap.h"
31 #include "radius_client.h"
32 #include "ieee802_1x.h"
33
34
35 static struct hostapd_config *hostapd_config_defaults(void)
36 {
37         struct hostapd_config *conf;
38
39         conf = malloc(sizeof(*conf) + sizeof(struct hostapd_radius_servers));
40         if (conf == NULL) {
41                 printf("Failed to allocate memory for configuration data.\n");
42                 return NULL;
43         }
44         memset(conf, 0, sizeof(*conf) + sizeof(struct hostapd_radius_servers));
45         conf->radius = (struct hostapd_radius_servers *) (conf + 1);
46
47         /* set default driver based on configuration */
48         conf->driver = driver_lookup("default");
49         if (conf->driver == NULL) {
50                 printf("No default driver registered!\n");
51                 free(conf);
52                 return NULL;
53         }
54
55         conf->wep_rekeying_period = 300;
56         conf->eap_reauth_period = 3600;
57
58         conf->logger_syslog_level = HOSTAPD_LEVEL_INFO;
59         conf->logger_stdout_level = HOSTAPD_LEVEL_INFO;
60         conf->logger_syslog = (unsigned int) -1;
61         conf->logger_stdout = (unsigned int) -1;
62
63         conf->auth_algs = HOSTAPD_AUTH_OPEN | HOSTAPD_AUTH_SHARED_KEY;
64         conf->eapol_version = EAPOL_VERSION;
65
66         conf->wpa_group_rekey = 600;
67         conf->wpa_gmk_rekey = 86400;
68         conf->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
69         conf->wpa_pairwise = WPA_CIPHER_TKIP;
70         conf->wpa_group = WPA_CIPHER_TKIP;
71
72         conf->radius_server_auth_port = 1812;
73
74         return conf;
75 }
76
77
78 static int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr)
79 {
80         if (inet_aton(txt, &addr->u.v4)) {
81                 addr->af = AF_INET;
82                 return 0;
83         }
84
85 #ifdef CONFIG_IPV6
86         if (inet_pton(AF_INET6, txt, &addr->u.v6) > 0) {
87                 addr->af = AF_INET6;
88                 return 0;
89         }
90 #endif /* CONFIG_IPV6 */
91
92         return -1;
93 }
94
95
96 static int mac_comp(const void *a, const void *b)
97 {
98         return memcmp(a, b, sizeof(macaddr));
99 }
100
101
102 static int hostapd_config_read_maclist(const char *fname, macaddr **acl,
103                                        int *num)
104 {
105         FILE *f;
106         char buf[128], *pos;
107         int line = 0;
108         u8 addr[ETH_ALEN];
109         macaddr *newacl;
110
111         if (!fname)
112                 return 0;
113
114         f = fopen(fname, "r");
115         if (!f) {
116                 printf("MAC list file '%s' not found.\n", fname);
117                 return -1;
118         }
119
120         while (fgets(buf, sizeof(buf), f)) {
121                 line++;
122
123                 if (buf[0] == '#')
124                         continue;
125                 pos = buf;
126                 while (*pos != '\0') {
127                         if (*pos == '\n') {
128                                 *pos = '\0';
129                                 break;
130                         }
131                         pos++;
132                 }
133                 if (buf[0] == '\0')
134                         continue;
135
136                 if (hwaddr_aton(buf, addr)) {
137                         printf("Invalid MAC address '%s' at line %d in '%s'\n",
138                                buf, line, fname);
139                         fclose(f);
140                         return -1;
141                 }
142
143                 newacl = (macaddr *) realloc(*acl, (*num + 1) * ETH_ALEN);
144                 if (newacl == NULL) {
145                         printf("MAC list reallocation failed\n");
146                         fclose(f);
147                         return -1;
148                 }
149
150                 *acl = newacl;
151                 memcpy((*acl)[*num], addr, ETH_ALEN);
152                 (*num)++;
153         }
154
155         fclose(f);
156
157         qsort(*acl, *num, sizeof(macaddr), mac_comp);
158
159         return 0;
160 }
161
162
163 static int hostapd_config_read_wpa_psk(const char *fname,
164                                        struct hostapd_config *conf)
165 {
166         FILE *f;
167         char buf[128], *pos;
168         int line = 0, ret = 0, len, ok;
169         u8 addr[ETH_ALEN];
170         struct hostapd_wpa_psk *psk;
171
172         if (!fname)
173                 return 0;
174
175         f = fopen(fname, "r");
176         if (!f) {
177                 printf("WPA PSK file '%s' not found.\n", fname);
178                 return -1;
179         }
180
181         while (fgets(buf, sizeof(buf), f)) {
182                 line++;
183
184                 if (buf[0] == '#')
185                         continue;
186                 pos = buf;
187                 while (*pos != '\0') {
188                         if (*pos == '\n') {
189                                 *pos = '\0';
190                                 break;
191                         }
192                         pos++;
193                 }
194                 if (buf[0] == '\0')
195                         continue;
196
197                 if (hwaddr_aton(buf, addr)) {
198                         printf("Invalid MAC address '%s' on line %d in '%s'\n",
199                                buf, line, fname);
200                         ret = -1;
201                         break;
202                 }
203
204                 psk = malloc(sizeof(*psk));
205                 if (psk == NULL) {
206                         printf("WPA PSK allocation failed\n");
207                         ret = -1;
208                         break;
209                 }
210                 memset(psk, 0, sizeof(*psk));
211                 if (memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
212                         psk->group = 1;
213                 else
214                         memcpy(psk->addr, addr, ETH_ALEN);
215
216                 pos = buf + 17;
217                 if (pos == '\0') {
218                         printf("No PSK on line %d in '%s'\n", line, fname);
219                         free(psk);
220                         ret = -1;
221                         break;
222                 }
223                 pos++;
224
225                 ok = 0;
226                 len = strlen(pos);
227                 if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
228                         ok = 1;
229                 else if (len >= 8 && len < 64) {
230                         pbkdf2_sha1(pos, conf->ssid, conf->ssid_len,
231                                     4096, psk->psk, PMK_LEN);
232                         ok = 1;
233                 }
234                 if (!ok) {
235                         printf("Invalid PSK '%s' on line %d in '%s'\n",
236                                pos, line, fname);
237                         free(psk);
238                         ret = -1;
239                         break;
240                 }
241
242                 psk->next = conf->wpa_psk;
243                 conf->wpa_psk = psk;
244         }
245
246         fclose(f);
247
248         return ret;
249 }
250
251
252 int hostapd_setup_wpa_psk(struct hostapd_config *conf)
253 {
254         if (conf->wpa_passphrase != NULL) {
255                 if (conf->wpa_psk != NULL) {
256                         printf("Warning: both WPA PSK and passphrase set. "
257                                "Using passphrase.\n");
258                         free(conf->wpa_psk);
259                 }
260                 conf->wpa_psk = malloc(sizeof(struct hostapd_wpa_psk));
261                 if (conf->wpa_psk == NULL) {
262                         printf("Unable to alloc space for PSK\n");
263                         return -1;
264                 }
265                 wpa_hexdump_ascii(MSG_DEBUG, "SSID",
266                                   (u8 *) conf->ssid, conf->ssid_len);
267                 wpa_hexdump_ascii(MSG_DEBUG, "PSK (ASCII passphrase)",
268                                   (u8 *) conf->wpa_passphrase,
269                                   strlen(conf->wpa_passphrase));
270                 memset(conf->wpa_psk, 0, sizeof(struct hostapd_wpa_psk));
271                 pbkdf2_sha1(conf->wpa_passphrase,
272                             conf->ssid, conf->ssid_len,
273                             4096, conf->wpa_psk->psk, PMK_LEN);
274                 wpa_hexdump(MSG_DEBUG, "PSK (from passphrase)",
275                             conf->wpa_psk->psk, PMK_LEN);
276                 conf->wpa_psk->group = 1;
277
278                 memset(conf->wpa_passphrase, 0, strlen(conf->wpa_passphrase));
279                 free(conf->wpa_passphrase);
280                 conf->wpa_passphrase = 0;
281         }
282
283         if (conf->wpa_psk_file) {
284                 if (hostapd_config_read_wpa_psk(conf->wpa_psk_file, conf))
285                         return -1;
286                 free(conf->wpa_psk_file);
287                 conf->wpa_psk_file = NULL;
288         }
289
290         return 0;
291 }
292
293
294 #ifdef EAP_SERVER
295 static int hostapd_config_read_eap_user(const char *fname,
296                                         struct hostapd_config *conf)
297 {
298         FILE *f;
299         char buf[512], *pos, *start, *pos2;
300         int line = 0, ret = 0, num_methods;
301         struct hostapd_eap_user *user, *tail = NULL;
302
303         if (!fname)
304                 return 0;
305
306         f = fopen(fname, "r");
307         if (!f) {
308                 printf("EAP user file '%s' not found.\n", fname);
309                 return -1;
310         }
311
312         /* Lines: "user" METHOD,METHOD2 "password" (password optional) */
313         while (fgets(buf, sizeof(buf), f)) {
314                 line++;
315
316                 if (buf[0] == '#')
317                         continue;
318                 pos = buf;
319                 while (*pos != '\0') {
320                         if (*pos == '\n') {
321                                 *pos = '\0';
322                                 break;
323                         }
324                         pos++;
325                 }
326                 if (buf[0] == '\0')
327                         continue;
328
329                 user = NULL;
330
331                 if (buf[0] != '"' && buf[0] != '*') {
332                         printf("Invalid EAP identity (no \" in start) on "
333                                "line %d in '%s'\n", line, fname);
334                         goto failed;
335                 }
336
337                 user = malloc(sizeof(*user));
338                 if (user == NULL) {
339                         printf("EAP user allocation failed\n");
340                         goto failed;
341                 }
342                 memset(user, 0, sizeof(*user));
343                 user->force_version = -1;
344
345                 if (buf[0] == '*') {
346                         pos = buf;
347                 } else {
348                         pos = buf + 1;
349                         start = pos;
350                         while (*pos != '"' && *pos != '\0')
351                                 pos++;
352                         if (*pos == '\0') {
353                                 printf("Invalid EAP identity (no \" in end) on"
354                                        " line %d in '%s'\n", line, fname);
355                                 goto failed;
356                         }
357
358                         user->identity = malloc(pos - start);
359                         if (user->identity == NULL) {
360                                 printf("Failed to allocate memory for EAP "
361                                        "identity\n");
362                                 goto failed;
363                         }
364                         memcpy(user->identity, start, pos - start);
365                         user->identity_len = pos - start;
366                 }
367                 pos++;
368                 while (*pos == ' ' || *pos == '\t')
369                         pos++;
370
371                 if (*pos == '\0') {
372                         printf("No EAP method on line %d in '%s'\n",
373                                line, fname);
374                         goto failed;
375                 }
376
377                 start = pos;
378                 while (*pos != ' ' && *pos != '\t' && *pos != '\0')
379                         pos++;
380                 if (*pos == '\0') {
381                         pos = NULL;
382                 } else {
383                         *pos = '\0';
384                         pos++;
385                 }
386                 num_methods = 0;
387                 while (*start) {
388                         char *pos2 = strchr(start, ',');
389                         if (pos2) {
390                                 *pos2++ = '\0';
391                         }
392                         user->methods[num_methods] = eap_get_type(start);
393                         if (user->methods[num_methods] == EAP_TYPE_NONE) {
394                                 printf("Unsupported EAP type '%s' on line %d "
395                                        "in '%s'\n", start, line, fname);
396                                 goto failed;
397                         }
398
399                         num_methods++;
400                         if (num_methods >= EAP_USER_MAX_METHODS)
401                                 break;
402                         if (pos2 == NULL)
403                                 break;
404                         start = pos2;
405                 }
406                 if (num_methods == 0) {
407                         printf("No EAP types configured on line %d in '%s'\n",
408                                line, fname);
409                         goto failed;
410                 }
411
412                 if (pos == NULL)
413                         goto done;
414
415                 while (*pos == ' ' || *pos == '\t')
416                         pos++;
417                 if (*pos == '\0')
418                         goto done;
419
420                 if (strncmp(pos, "[ver=0]", 7) == 0) {
421                         user->force_version = 0;
422                         goto done;
423                 }
424
425                 if (strncmp(pos, "[ver=1]", 7) == 0) {
426                         user->force_version = 1;
427                         goto done;
428                 }
429
430                 if (strncmp(pos, "[2]", 3) == 0) {
431                         user->phase2 = 1;
432                         goto done;
433                 }
434
435                 if (*pos == '"') {
436                         pos++;
437                         start = pos;
438                         while (*pos != '"' && *pos != '\0')
439                                 pos++;
440                         if (*pos == '\0') {
441                                 printf("Invalid EAP password (no \" in end) "
442                                        "on line %d in '%s'\n", line, fname);
443                                 goto failed;
444                         }
445
446                         user->password = malloc(pos - start);
447                         if (user->password == NULL) {
448                                 printf("Failed to allocate memory for EAP "
449                                        "password\n");
450                                 goto failed;
451                         }
452                         memcpy(user->password, start, pos - start);
453                         user->password_len = pos - start;
454
455                         pos++;
456                 } else {
457                         pos2 = pos;
458                         while (*pos2 != '\0' && *pos2 != ' ' &&
459                                *pos2 != '\t' && *pos2 != '#')
460                                 pos2++;
461                         if ((pos2 - pos) & 1) {
462                                 printf("Invalid hex password on line %d in "
463                                        "'%s'\n", line, fname);
464                                 goto failed;
465                         }
466                         user->password = malloc((pos2 - pos) / 2);
467                         if (user->password == NULL) {
468                                 printf("Failed to allocate memory for EAP "
469                                        "password\n");
470                                 goto failed;
471                         }
472                         if (hexstr2bin(pos, user->password,
473                                        (pos2 - pos) / 2) < 0) {
474                                 printf("Invalid hex password on line %d in "
475                                        "'%s'\n", line, fname);
476                                 goto failed;
477                         }
478                         user->password_len = (pos2 - pos) / 2;
479                         pos = pos2;
480                 }
481
482                 while (*pos == ' ' || *pos == '\t')
483                         pos++;
484                 if (strncmp(pos, "[2]", 3) == 0) {
485                         user->phase2 = 1;
486                 }
487
488         done:
489                 if (tail == NULL) {
490                         tail = conf->eap_user = user;
491                 } else {
492                         tail->next = user;
493                         tail = user;
494                 }
495                 continue;
496
497         failed:
498                 if (user) {
499                         free(user->identity);
500                         free(user);
501                 }
502                 ret = -1;
503                 break;
504         }
505
506         fclose(f);
507
508         return ret;
509 }
510 #endif /* EAP_SERVER */
511
512
513 static int
514 hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
515                                 int *num_server, const char *val, int def_port,
516                                 struct hostapd_radius_server **curr_serv)
517 {
518         struct hostapd_radius_server *nserv;
519         int ret;
520         static int server_index = 1;
521
522         nserv = realloc(*server, (*num_server + 1) * sizeof(*nserv));
523         if (nserv == NULL)
524                 return -1;
525
526         *server = nserv;
527         nserv = &nserv[*num_server];
528         (*num_server)++;
529         (*curr_serv) = nserv;
530
531         memset(nserv, 0, sizeof(*nserv));
532         nserv->port = def_port;
533         ret = hostapd_parse_ip_addr(val, &nserv->addr);
534         nserv->index = server_index++;
535
536         return ret;
537 }
538
539
540 static int hostapd_config_parse_key_mgmt(int line, const char *value)
541 {
542         int val = 0, last;
543         char *start, *end, *buf;
544
545         buf = strdup(value);
546         if (buf == NULL)
547                 return -1;
548         start = buf;
549
550         while (start != '\0') {
551                 while (*start == ' ' || *start == '\t')
552                         start++;
553                 if (*start == '\0')
554                         break;
555                 end = start;
556                 while (*end != ' ' && *end != '\t' && *end != '\0')
557                         end++;
558                 last = *end == '\0';
559                 *end = '\0';
560                 if (strcmp(start, "WPA-PSK") == 0)
561                         val |= WPA_KEY_MGMT_PSK;
562                 else if (strcmp(start, "WPA-EAP") == 0)
563                         val |= WPA_KEY_MGMT_IEEE8021X;
564                 else {
565                         printf("Line %d: invalid key_mgmt '%s'", line, start);
566                         free(buf);
567                         return -1;
568                 }
569
570                 if (last)
571                         break;
572                 start = end + 1;
573         }
574
575         free(buf);
576         if (val == 0) {
577                 printf("Line %d: no key_mgmt values configured.", line);
578                 return -1;
579         }
580
581         return val;
582 }
583
584
585 static int hostapd_config_parse_cipher(int line, const char *value)
586 {
587         int val = 0, last;
588         char *start, *end, *buf;
589
590         buf = strdup(value);
591         if (buf == NULL)
592                 return -1;
593         start = buf;
594
595         while (start != '\0') {
596                 while (*start == ' ' || *start == '\t')
597                         start++;
598                 if (*start == '\0')
599                         break;
600                 end = start;
601                 while (*end != ' ' && *end != '\t' && *end != '\0')
602                         end++;
603                 last = *end == '\0';
604                 *end = '\0';
605                 if (strcmp(start, "CCMP") == 0)
606                         val |= WPA_CIPHER_CCMP;
607                 else if (strcmp(start, "TKIP") == 0)
608                         val |= WPA_CIPHER_TKIP;
609                 else if (strcmp(start, "WEP104") == 0)
610                         val |= WPA_CIPHER_WEP104;
611                 else if (strcmp(start, "WEP40") == 0)
612                         val |= WPA_CIPHER_WEP40;
613                 else if (strcmp(start, "NONE") == 0)
614                         val |= WPA_CIPHER_NONE;
615                 else {
616                         printf("Line %d: invalid cipher '%s'.", line, start);
617                         free(buf);
618                         return -1;
619                 }
620
621                 if (last)
622                         break;
623                 start = end + 1;
624         }
625         free(buf);
626
627         if (val == 0) {
628                 printf("Line %d: no cipher values configured.", line);
629                 return -1;
630         }
631         return val;
632 }
633
634
635 static int hostapd_config_check(struct hostapd_config *conf)
636 {
637         if (conf->ieee802_1x && !conf->eap_server &&
638             !conf->radius->auth_servers) {
639                 printf("Invalid IEEE 802.1X configuration (no EAP "
640                        "authenticator configured).\n");
641                 return -1;
642         }
643
644         if (conf->wpa && (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
645             conf->wpa_psk == NULL && conf->wpa_passphrase == NULL &&
646             conf->wpa_psk_file == NULL) {
647                 printf("WPA-PSK enabled, but PSK or passphrase is not "
648                        "configured.\n");
649                 return -1;
650         }
651
652         return 0;
653 }
654
655
656 struct hostapd_config * hostapd_config_read(const char *fname)
657 {
658         struct hostapd_config *conf;
659         FILE *f;
660         char buf[256], *pos;
661         int line = 0;
662         int errors = 0;
663         char *accept_mac_file = NULL, *deny_mac_file = NULL;
664 #ifdef EAP_SERVER
665         char *eap_user_file = NULL;
666 #endif /* EAP_SERVER */
667
668         f = fopen(fname, "r");
669         if (f == NULL) {
670                 printf("Could not open configuration file '%s' for reading.\n",
671                        fname);
672                 return NULL;
673         }
674
675         conf = hostapd_config_defaults();
676         if (conf == NULL) {
677                 fclose(f);
678                 return NULL;
679         }
680
681         while (fgets(buf, sizeof(buf), f)) {
682                 line++;
683
684                 if (buf[0] == '#')
685                         continue;
686                 pos = buf;
687                 while (*pos != '\0') {
688                         if (*pos == '\n') {
689                                 *pos = '\0';
690                                 break;
691                         }
692                         pos++;
693                 }
694                 if (buf[0] == '\0')
695                         continue;
696
697                 pos = strchr(buf, '=');
698                 if (pos == NULL) {
699                         printf("Line %d: invalid line '%s'\n", line, buf);
700                         errors++;
701                         continue;
702                 }
703                 *pos = '\0';
704                 pos++;
705
706                 if (strcmp(buf, "interface") == 0) {
707                         snprintf(conf->iface, sizeof(conf->iface), "%s", pos);
708                 } else if (strcmp(buf, "bridge") == 0) {
709                         snprintf(conf->bridge, sizeof(conf->bridge), "%s",
710                                  pos);
711                 } else if (strcmp(buf, "driver") == 0) {
712                         conf->driver = driver_lookup(pos);
713                         if (conf->driver == NULL) {
714                                 printf("Line %d: invalid/unknown driver "
715                                        "'%s'\n", line, pos);
716                                 errors++;
717                         }
718                 } else if (strcmp(buf, "debug") == 0) {
719                         conf->debug = atoi(pos);
720                 } else if (strcmp(buf, "logger_syslog_level") == 0) {
721                         conf->logger_syslog_level = atoi(pos);
722                 } else if (strcmp(buf, "logger_stdout_level") == 0) {
723                         conf->logger_stdout_level = atoi(pos);
724                 } else if (strcmp(buf, "logger_syslog") == 0) {
725                         conf->logger_syslog = atoi(pos);
726                 } else if (strcmp(buf, "logger_stdout") == 0) {
727                         conf->logger_stdout = atoi(pos);
728                 } else if (strcmp(buf, "dump_file") == 0) {
729                         conf->dump_log_name = strdup(pos);
730                 } else if (strcmp(buf, "ssid") == 0) {
731                         conf->ssid_len = strlen(pos);
732                         if (conf->ssid_len >= HOSTAPD_SSID_LEN ||
733                             conf->ssid_len < 1) {
734                                 printf("Line %d: invalid SSID '%s'\n", line,
735                                        pos);
736                                 errors++;
737                         }
738                         memcpy(conf->ssid, pos, conf->ssid_len);
739                         conf->ssid[conf->ssid_len] = '\0';
740                         conf->ssid_set = 1;
741                 } else if (strcmp(buf, "macaddr_acl") == 0) {
742                         conf->macaddr_acl = atoi(pos);
743                         if (conf->macaddr_acl != ACCEPT_UNLESS_DENIED &&
744                             conf->macaddr_acl != DENY_UNLESS_ACCEPTED &&
745                             conf->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
746                                 printf("Line %d: unknown macaddr_acl %d\n",
747                                        line, conf->macaddr_acl);
748                         }
749                 } else if (strcmp(buf, "accept_mac_file") == 0) {
750                         accept_mac_file = strdup(pos);
751                         if (!accept_mac_file) {
752                                 printf("Line %d: allocation failed\n", line);
753                                 errors++;
754                         }
755                 } else if (strcmp(buf, "deny_mac_file") == 0) {
756                         deny_mac_file = strdup(pos);
757                         if (!deny_mac_file) {
758                                 printf("Line %d: allocation failed\n", line);
759                                 errors++;
760                         }
761                 } else if (strcmp(buf, "assoc_ap_addr") == 0) {
762                         if (hwaddr_aton(pos, conf->assoc_ap_addr)) {
763                                 printf("Line %d: invalid MAC address '%s'\n",
764                                        line, pos);
765                                 errors++;
766                         }
767                         conf->assoc_ap = 1;
768                 } else if (strcmp(buf, "ieee8021x") == 0) {
769                         conf->ieee802_1x = atoi(pos);
770                 } else if (strcmp(buf, "eapol_version") == 0) {
771                         conf->eapol_version = atoi(pos);
772                         if (conf->eapol_version < 1 ||
773                             conf->eapol_version > 2) {
774                                 printf("Line %d: invalid EAPOL "
775                                        "version (%d): '%s'.\n",
776                                        line, conf->eapol_version, pos);
777                                 errors++;
778                         } else
779                                 wpa_printf(MSG_DEBUG, "eapol_version=%d",
780                                            conf->eapol_version);
781 #ifdef EAP_SERVER
782                 } else if (strcmp(buf, "eap_authenticator") == 0) {
783                         conf->eap_server = atoi(pos);
784                         printf("Line %d: obsolete eap_authenticator used; "
785                                "this has been renamed to eap_server\n", line);
786                 } else if (strcmp(buf, "eap_server") == 0) {
787                         conf->eap_server = atoi(pos);
788                 } else if (strcmp(buf, "eap_user_file") == 0) {
789                         free(eap_user_file);
790                         eap_user_file = strdup(pos);
791                         if (!eap_user_file) {
792                                 printf("Line %d: allocation failed\n", line);
793                                 errors++;
794                         }
795                 } else if (strcmp(buf, "ca_cert") == 0) {
796                         free(conf->ca_cert);
797                         conf->ca_cert = strdup(pos);
798                 } else if (strcmp(buf, "server_cert") == 0) {
799                         free(conf->server_cert);
800                         conf->server_cert = strdup(pos);
801                 } else if (strcmp(buf, "private_key") == 0) {
802                         free(conf->private_key);
803                         conf->private_key = strdup(pos);
804                 } else if (strcmp(buf, "private_key_passwd") == 0) {
805                         free(conf->private_key_passwd);
806                         conf->private_key_passwd = strdup(pos);
807                 } else if (strcmp(buf, "check_crl") == 0) {
808                         conf->check_crl = atoi(pos);
809 #ifdef EAP_SIM
810                 } else if (strcmp(buf, "eap_sim_db") == 0) {
811                         free(conf->eap_sim_db);
812                         conf->eap_sim_db = strdup(pos);
813 #endif /* EAP_SIM */
814 #endif /* EAP_SERVER */
815                 } else if (strcmp(buf, "eap_message") == 0) {
816                         char *term;
817                         conf->eap_req_id_text = strdup(pos);
818                         if (conf->eap_req_id_text == NULL) {
819                                 printf("Line %d: Failed to allocate memory "
820                                        "for eap_req_id_text\n", line);
821                                 errors++;
822                                 continue;
823                         }
824                         conf->eap_req_id_text_len =
825                                 strlen(conf->eap_req_id_text);
826                         term = strstr(conf->eap_req_id_text, "\\0");
827                         if (term) {
828                                 *term++ = '\0';
829                                 memmove(term, term + 1,
830                                         conf->eap_req_id_text_len -
831                                         (term - conf->eap_req_id_text) - 1);
832                                 conf->eap_req_id_text_len--;
833                         }
834                 } else if (strcmp(buf, "wep_key_len_broadcast") == 0) {
835                         conf->default_wep_key_len = atoi(pos);
836                         if (conf->default_wep_key_len > 13) {
837                                 printf("Line %d: invalid WEP key len %lu "
838                                        "(= %lu bits)\n", line,
839                                        (unsigned long)
840                                        conf->default_wep_key_len,
841                                        (unsigned long)
842                                        conf->default_wep_key_len * 8);
843                                 errors++;
844                         }
845                 } else if (strcmp(buf, "wep_key_len_unicast") == 0) {
846                         conf->individual_wep_key_len = atoi(pos);
847                         if (conf->individual_wep_key_len < 0 ||
848                             conf->individual_wep_key_len > 13) {
849                                 printf("Line %d: invalid WEP key len %d "
850                                        "(= %d bits)\n", line,
851                                        conf->individual_wep_key_len,
852                                        conf->individual_wep_key_len * 8);
853                                 errors++;
854                         }
855                 } else if (strcmp(buf, "wep_rekey_period") == 0) {
856                         conf->wep_rekeying_period = atoi(pos);
857                         if (conf->wep_rekeying_period < 0) {
858                                 printf("Line %d: invalid period %d\n",
859                                        line, conf->wep_rekeying_period);
860                                 errors++;
861                         }
862                 } else if (strcmp(buf, "eap_reauth_period") == 0) {
863                         conf->eap_reauth_period = atoi(pos);
864                         if (conf->eap_reauth_period < 0) {
865                                 printf("Line %d: invalid period %d\n",
866                                        line, conf->eap_reauth_period);
867                                 errors++;
868                         }
869                 } else if (strcmp(buf, "eapol_key_index_workaround") == 0) {
870                         conf->eapol_key_index_workaround = atoi(pos);
871 #ifdef CONFIG_IAPP
872                 } else if (strcmp(buf, "iapp_interface") == 0) {
873                         conf->ieee802_11f = 1;
874                         snprintf(conf->iapp_iface, sizeof(conf->iapp_iface),
875                                  "%s", pos);
876 #endif /* CONFIG_IAPP */
877                 } else if (strcmp(buf, "own_ip_addr") == 0) {
878                         if (hostapd_parse_ip_addr(pos, &conf->own_ip_addr)) {
879                                 printf("Line %d: invalid IP address '%s'\n",
880                                        line, pos);
881                                 errors++;
882                         }
883                 } else if (strcmp(buf, "nas_identifier") == 0) {
884                         conf->nas_identifier = strdup(pos);
885                 } else if (strcmp(buf, "auth_server_addr") == 0) {
886                         if (hostapd_config_read_radius_addr(
887                                     &conf->radius->auth_servers,
888                                     &conf->radius->num_auth_servers, pos, 1812,
889                                     &conf->radius->auth_server)) {
890                                 printf("Line %d: invalid IP address '%s'\n",
891                                        line, pos);
892                                 errors++;
893                         }
894                 } else if (conf->radius->auth_server &&
895                            strcmp(buf, "auth_server_port") == 0) {
896                         conf->radius->auth_server->port = atoi(pos);
897                 } else if (conf->radius->auth_server &&
898                            strcmp(buf, "auth_server_shared_secret") == 0) {
899                         int len = strlen(pos);
900                         if (len == 0) {
901                                 /* RFC 2865, Ch. 3 */
902                                 printf("Line %d: empty shared secret is not "
903                                        "allowed.\n", line);
904                                 errors++;
905                         }
906                         conf->radius->auth_server->shared_secret =
907                                 (u8 *) strdup(pos);
908                         conf->radius->auth_server->shared_secret_len = len;
909                 } else if (strcmp(buf, "acct_server_addr") == 0) {
910                         if (hostapd_config_read_radius_addr(
911                                     &conf->radius->acct_servers,
912                                     &conf->radius->num_acct_servers, pos, 1813,
913                                     &conf->radius->acct_server)) {
914                                 printf("Line %d: invalid IP address '%s'\n",
915                                        line, pos);
916                                 errors++;
917                         }
918                 } else if (conf->radius->acct_server &&
919                            strcmp(buf, "acct_server_port") == 0) {
920                         conf->radius->acct_server->port = atoi(pos);
921                 } else if (conf->radius->acct_server &&
922                            strcmp(buf, "acct_server_shared_secret") == 0) {
923                         int len = strlen(pos);
924                         if (len == 0) {
925                                 /* RFC 2865, Ch. 3 */
926                                 printf("Line %d: empty shared secret is not "
927                                        "allowed.\n", line);
928                                 errors++;
929                         }
930                         conf->radius->acct_server->shared_secret =
931                                 (u8 *) strdup(pos);
932                         conf->radius->acct_server->shared_secret_len = len;
933                 } else if (strcmp(buf, "radius_retry_primary_interval") == 0) {
934                         conf->radius->retry_primary_interval = atoi(pos);
935                 } else if (strcmp(buf, "radius_acct_interim_interval") == 0) {
936                         conf->radius->acct_interim_interval = atoi(pos);
937                 } else if (strcmp(buf, "auth_algs") == 0) {
938                         conf->auth_algs = atoi(pos);
939                         if (conf->auth_algs == 0) {
940                                 printf("Line %d: no authentication algorithms "
941                                        "allowed\n",
942                                        line);
943                                 errors++;
944                         }
945                 } else if (strcmp(buf, "wpa") == 0) {
946                         conf->wpa = atoi(pos);
947                 } else if (strcmp(buf, "wpa_group_rekey") == 0) {
948                         conf->wpa_group_rekey = atoi(pos);
949                 } else if (strcmp(buf, "wpa_strict_rekey") == 0) {
950                         conf->wpa_strict_rekey = atoi(pos);
951                 } else if (strcmp(buf, "wpa_gmk_rekey") == 0) {
952                         conf->wpa_gmk_rekey = atoi(pos);
953                 } else if (strcmp(buf, "wpa_passphrase") == 0) {
954                         int len = strlen(pos);
955                         if (len < 8 || len > 63) {
956                                 printf("Line %d: invalid WPA passphrase length"
957                                        " %d (expected 8..63)\n", line, len);
958                                 errors++;
959                         } else {
960                                 free(conf->wpa_passphrase);
961                                 conf->wpa_passphrase = strdup(pos);
962                         }
963                 } else if (strcmp(buf, "wpa_psk") == 0) {
964                         free(conf->wpa_psk);
965                         conf->wpa_psk = malloc(sizeof(struct hostapd_wpa_psk));
966                         if (conf->wpa_psk) {
967                                 memset(conf->wpa_psk, 0,
968                                        sizeof(struct hostapd_wpa_psk));
969                         }
970                         if (conf->wpa_psk == NULL)
971                                 errors++;
972                         else if (hexstr2bin(pos, conf->wpa_psk->psk, PMK_LEN)
973                                  || pos[PMK_LEN * 2] != '\0') {
974                                 printf("Line %d: Invalid PSK '%s'.\n", line,
975                                        pos);
976                                 errors++;
977                         } else {
978                                 conf->wpa_psk->group = 1;
979                         }
980                 } else if (strcmp(buf, "wpa_psk_file") == 0) {
981                         free(conf->wpa_psk_file);
982                         conf->wpa_psk_file = strdup(pos);
983                         if (!conf->wpa_psk_file) {
984                                 printf("Line %d: allocation failed\n", line);
985                                 errors++;
986                         }
987                 } else if (strcmp(buf, "wpa_key_mgmt") == 0) {
988                         conf->wpa_key_mgmt =
989                                 hostapd_config_parse_key_mgmt(line, pos);
990                         if (conf->wpa_key_mgmt == -1)
991                                 errors++;
992                 } else if (strcmp(buf, "wpa_pairwise") == 0) {
993                         conf->wpa_pairwise =
994                                 hostapd_config_parse_cipher(line, pos);
995                         if (conf->wpa_pairwise == -1 ||
996                             conf->wpa_pairwise == 0)
997                                 errors++;
998                         else if (conf->wpa_pairwise &
999                                  (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
1000                                   WPA_CIPHER_WEP104)) {
1001                                 printf("Line %d: unsupported pairwise "
1002                                        "cipher suite '%s'\n",
1003                                        conf->wpa_pairwise, pos);
1004                                 errors++;
1005                         } else {
1006                                 if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
1007                                         conf->wpa_group = WPA_CIPHER_TKIP;
1008                                 else
1009                                         conf->wpa_group = WPA_CIPHER_CCMP;
1010                         }
1011 #ifdef CONFIG_RSN_PREAUTH
1012                 } else if (strcmp(buf, "rsn_preauth") == 0) {
1013                         conf->rsn_preauth = atoi(pos);
1014                 } else if (strcmp(buf, "rsn_preauth_interfaces") == 0) {
1015                         conf->rsn_preauth_interfaces = strdup(pos);
1016 #endif /* CONFIG_RSN_PREAUTH */
1017                 } else if (strcmp(buf, "ctrl_interface") == 0) {
1018                         free(conf->ctrl_interface);
1019                         conf->ctrl_interface = strdup(pos);
1020                 } else if (strcmp(buf, "ctrl_interface_group") == 0) {
1021                         struct group *grp;
1022                         char *endp;
1023                         const char *group = pos;
1024
1025                         grp = getgrnam(group);
1026                         if (grp) {
1027                                 conf->ctrl_interface_gid = grp->gr_gid;
1028                                 conf->ctrl_interface_gid_set = 1;
1029                                 wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
1030                                            " (from group name '%s')",
1031                                            conf->ctrl_interface_gid, group);
1032                                 continue;
1033                         }
1034
1035                         /* Group name not found - try to parse this as gid */
1036                         conf->ctrl_interface_gid = strtol(group, &endp, 10);
1037                         if (*group == '\0' || *endp != '\0') {
1038                                 wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
1039                                            "'%s'", line, group);
1040                                 errors++;
1041                                 continue;
1042                         }
1043                         conf->ctrl_interface_gid_set = 1;
1044                         wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
1045                                    conf->ctrl_interface_gid);
1046 #ifdef RADIUS_SERVER
1047                 } else if (strcmp(buf, "radius_server_clients") == 0) {
1048                         free(conf->radius_server_clients);
1049                         conf->radius_server_clients = strdup(pos);
1050                 } else if (strcmp(buf, "radius_server_auth_port") == 0) {
1051                         conf->radius_server_auth_port = atoi(pos);
1052                 } else if (strcmp(buf, "radius_server_ipv6") == 0) {
1053                         conf->radius_server_ipv6 = atoi(pos);
1054 #endif /* RADIUS_SERVER */
1055                 } else if (strcmp(buf, "test_socket") == 0) {
1056                         free(conf->test_socket);
1057                         conf->test_socket = strdup(pos);
1058                 } else if (strcmp(buf, "use_pae_group_addr") == 0) {
1059                         conf->use_pae_group_addr = atoi(pos);
1060                 } else {
1061                         printf("Line %d: unknown configuration item '%s'\n",
1062                                line, buf);
1063                         errors++;
1064                 }
1065         }
1066
1067         fclose(f);
1068
1069         if (hostapd_config_read_maclist(accept_mac_file, &conf->accept_mac,
1070                                         &conf->num_accept_mac))
1071                 errors++;
1072         free(accept_mac_file);
1073         if (hostapd_config_read_maclist(deny_mac_file, &conf->deny_mac,
1074                                         &conf->num_deny_mac))
1075                 errors++;
1076         free(deny_mac_file);
1077
1078 #ifdef EAP_SERVER
1079         if (hostapd_config_read_eap_user(eap_user_file, conf))
1080                 errors++;
1081         free(eap_user_file);
1082 #endif /* EAP_SERVER */
1083
1084         conf->radius->auth_server = conf->radius->auth_servers;
1085         conf->radius->acct_server = conf->radius->acct_servers;
1086
1087         if (hostapd_config_check(conf))
1088                 errors++;
1089
1090         if (errors) {
1091                 printf("%d errors found in configuration file '%s'\n",
1092                        errors, fname);
1093                 hostapd_config_free(conf);
1094                 conf = NULL;
1095         }
1096
1097         return conf;
1098 }
1099
1100
1101 static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
1102                                        int num_servers)
1103 {
1104         int i;
1105
1106         for (i = 0; i < num_servers; i++) {
1107                 free(servers[i].shared_secret);
1108         }
1109         free(servers);
1110 }
1111
1112
1113 static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
1114 {
1115         free(user->identity);
1116         free(user->password);
1117         free(user);
1118 }
1119
1120
1121 void hostapd_config_free(struct hostapd_config *conf)
1122 {
1123         struct hostapd_wpa_psk *psk, *prev;
1124         struct hostapd_eap_user *user, *prev_user;
1125
1126         if (conf == NULL)
1127                 return;
1128
1129         psk = conf->wpa_psk;
1130         while (psk) {
1131                 prev = psk;
1132                 psk = psk->next;
1133                 free(prev);
1134         }
1135
1136         free(conf->wpa_passphrase);
1137         free(conf->wpa_psk_file);
1138
1139         user = conf->eap_user;
1140         while (user) {
1141                 prev_user = user;
1142                 user = user->next;
1143                 hostapd_config_free_eap_user(prev_user);
1144         }
1145
1146         free(conf->dump_log_name);
1147         free(conf->eap_req_id_text);
1148         free(conf->accept_mac);
1149         free(conf->deny_mac);
1150         free(conf->nas_identifier);
1151         hostapd_config_free_radius(conf->radius->auth_servers,
1152                                    conf->radius->num_auth_servers);
1153         hostapd_config_free_radius(conf->radius->acct_servers,
1154                                    conf->radius->num_acct_servers);
1155         free(conf->rsn_preauth_interfaces);
1156         free(conf->ctrl_interface);
1157         free(conf->ca_cert);
1158         free(conf->server_cert);
1159         free(conf->private_key);
1160         free(conf->private_key_passwd);
1161         free(conf->eap_sim_db);
1162         free(conf->radius_server_clients);
1163         free(conf->test_socket);
1164         free(conf);
1165 }
1166
1167
1168 /* Perform a binary search for given MAC address from a pre-sorted list.
1169  * Returns 1 if address is in the list or 0 if not. */
1170 int hostapd_maclist_found(macaddr *list, int num_entries, u8 *addr)
1171 {
1172         int start, end, middle, res;
1173
1174         start = 0;
1175         end = num_entries - 1;
1176
1177         while (start <= end) {
1178                 middle = (start + end) / 2;
1179                 res = memcmp(list[middle], addr, ETH_ALEN);
1180                 if (res == 0)
1181                         return 1;
1182                 if (res < 0)
1183                         start = middle + 1;
1184                 else
1185                         end = middle - 1;
1186         }
1187
1188         return 0;
1189 }
1190
1191
1192 const u8 * hostapd_get_psk(const struct hostapd_config *conf, const u8 *addr,
1193                            const u8 *prev_psk)
1194 {
1195         struct hostapd_wpa_psk *psk;
1196         int next_ok = prev_psk == NULL;
1197
1198         for (psk = conf->wpa_psk; psk != NULL; psk = psk->next) {
1199                 if (next_ok &&
1200                     (psk->group || memcmp(psk->addr, addr, ETH_ALEN) == 0))
1201                         return psk->psk;
1202
1203                 if (psk->psk == prev_psk)
1204                         next_ok = 1;
1205         }
1206
1207         return NULL;
1208 }
1209
1210
1211 const struct hostapd_eap_user *
1212 hostapd_get_eap_user(const struct hostapd_config *conf, const u8 *identity,
1213                      size_t identity_len, int phase2)
1214 {
1215         struct hostapd_eap_user *user = conf->eap_user;
1216
1217         while (user) {
1218                 if (!phase2 && user->identity == NULL) {
1219                         /* Wildcard match */
1220                         break;
1221                 }
1222                 if (user->phase2 == !!phase2 &&
1223                     user->identity_len == identity_len &&
1224                     memcmp(user->identity, identity, identity_len) == 0)
1225                         break;
1226                 user = user->next;
1227         }
1228
1229         return user;
1230 }