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