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