Import of hostapd 0.4.9
[dragonfly.git] / contrib / hostapd-0.4.9 / radius_server.c
blob13c17744e091ad48f5d1e93a235d185d2ee257c8
1 /*
2 * hostapd / RADIUS authentication server
3 * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 2 as
7 * published by the Free Software Foundation.
9 * Alternatively, this software may be distributed under the terms of BSD
10 * license.
12 * See README and COPYING for more details.
15 #include <stdlib.h>
16 #include <stdio.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <netinet/in.h>
20 #include <sys/socket.h>
21 #include <arpa/inet.h>
22 #include <net/if.h>
24 #include "common.h"
25 #include "radius.h"
26 #include "eloop.h"
27 #include "config.h"
28 #include "eap.h"
29 #include "radius_server.h"
31 #define RADIUS_SESSION_TIMEOUT 60
32 #define RADIUS_MAX_SESSION 100
33 #define RADIUS_MAX_MSG_LEN 3000
35 static struct eapol_callbacks radius_server_eapol_cb;
37 struct radius_client;
38 struct radius_server_data;
40 struct radius_session {
41 struct radius_session *next;
42 struct radius_client *client;
43 struct radius_server_data *server;
44 unsigned int sess_id;
45 struct eap_sm *eap;
46 u8 *eapKeyData, *eapReqData;
47 size_t eapKeyDataLen, eapReqDataLen;
48 Boolean eapSuccess, eapRestart, eapFail, eapResp, eapReq, eapNoReq;
49 Boolean portEnabled, eapTimeout;
52 struct radius_client {
53 struct radius_client *next;
54 struct in_addr addr;
55 struct in_addr mask;
56 #ifdef CONFIG_IPV6
57 struct in6_addr addr6;
58 struct in6_addr mask6;
59 #endif /* CONFIG_IPV6 */
60 char *shared_secret;
61 int shared_secret_len;
62 struct radius_session *sessions;
65 struct radius_server_data {
66 int auth_sock;
67 struct radius_client *clients;
68 struct radius_server_session *sessions;
69 unsigned int next_sess_id;
70 void *hostapd_conf;
71 int num_sess;
72 void *eap_sim_db_priv;
73 void *ssl_ctx;
74 int ipv6;
78 extern int wpa_debug_level;
80 #define RADIUS_DEBUG(args...) \
81 wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
82 #define RADIUS_ERROR(args...) \
83 wpa_printf(MSG_ERROR, "RADIUS SRV: " args)
84 #define RADIUS_DUMP(args...) \
85 wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
86 #define RADIUS_DUMP_ASCII(args...) \
87 wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
90 static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
94 static struct radius_client *
95 radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
96 int ipv6)
98 struct radius_client *client = data->clients;
100 while (client) {
101 #ifdef CONFIG_IPV6
102 if (ipv6) {
103 struct in6_addr *addr6;
104 int i;
106 addr6 = (struct in6_addr *) addr;
107 for (i = 0; i < 16; i++) {
108 if ((addr6->s6_addr[i] &
109 client->mask6.s6_addr[i]) !=
110 (client->addr6.s6_addr[i] &
111 client->mask6.s6_addr[i])) {
112 i = 17;
113 break;
116 if (i == 16) {
117 break;
120 #endif /* CONFIG_IPV6 */
121 if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
122 (addr->s_addr & client->mask.s_addr)) {
123 break;
126 client = client->next;
129 return client;
133 static struct radius_session *
134 radius_server_get_session(struct radius_client *client, unsigned int sess_id)
136 struct radius_session *sess = client->sessions;
138 while (sess) {
139 if (sess->sess_id == sess_id) {
140 break;
142 sess = sess->next;
145 return sess;
149 static void radius_server_session_free(struct radius_server_data *data,
150 struct radius_session *sess)
152 eloop_cancel_timeout(radius_server_session_timeout, data, sess);
153 free(sess->eapKeyData);
154 free(sess->eapReqData);
155 eap_sm_deinit(sess->eap);
156 free(sess);
157 data->num_sess--;
161 static void radius_server_session_remove(struct radius_server_data *data,
162 struct radius_session *sess)
164 struct radius_client *client = sess->client;
165 struct radius_session *session, *prev;
167 prev = NULL;
168 session = client->sessions;
169 while (session) {
170 if (session == sess) {
171 if (prev == NULL) {
172 client->sessions = sess->next;
173 } else {
174 prev->next = sess->next;
176 radius_server_session_free(data, sess);
177 break;
179 prev = session;
180 session = session->next;
185 static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
187 struct radius_server_data *data = eloop_ctx;
188 struct radius_session *sess = timeout_ctx;
190 RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);
191 radius_server_session_remove(data, sess);
195 static struct radius_session *
196 radius_server_new_session(struct radius_server_data *data,
197 struct radius_client *client)
199 struct radius_session *sess;
201 if (data->num_sess >= RADIUS_MAX_SESSION) {
202 RADIUS_DEBUG("Maximum number of existing session - no room "
203 "for a new session");
204 return NULL;
207 sess = malloc(sizeof(*sess));
208 if (sess == NULL) {
209 return NULL;
211 memset(sess, 0, sizeof(*sess));
212 sess->server = data;
213 sess->client = client;
214 sess->sess_id = data->next_sess_id++;
215 sess->next = client->sessions;
216 client->sessions = sess;
217 eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,
218 radius_server_session_timeout, data, sess);
219 data->num_sess++;
220 return sess;
224 static struct radius_session *
225 radius_server_get_new_session(struct radius_server_data *data,
226 struct radius_client *client,
227 struct radius_msg *msg)
229 u8 *user;
230 size_t user_len;
231 const struct hostapd_eap_user *eap_user;
232 int res;
233 struct radius_session *sess;
234 struct eap_config eap_conf;
236 RADIUS_DEBUG("Creating a new session");
238 user = malloc(256);
239 if (user == NULL) {
240 return NULL;
242 res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
243 if (res < 0 || res > 256) {
244 RADIUS_DEBUG("Could not get User-Name");
245 free(user);
246 return NULL;
248 user_len = res;
249 RADIUS_DUMP_ASCII("User-Name", user, user_len);
251 eap_user = hostapd_get_eap_user(data->hostapd_conf, user, user_len, 0);
252 free(user);
254 if (eap_user) {
255 RADIUS_DEBUG("Matching user entry found");
256 sess = radius_server_new_session(data, client);
257 if (sess == NULL) {
258 RADIUS_DEBUG("Failed to create a new session");
259 return NULL;
261 } else {
262 RADIUS_DEBUG("User-Name not found from user database");
263 return NULL;
266 memset(&eap_conf, 0, sizeof(eap_conf));
267 eap_conf.ssl_ctx = data->ssl_ctx;
268 eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
269 eap_conf.backend_auth = TRUE;
270 sess->eap = eap_sm_init(sess, &radius_server_eapol_cb, &eap_conf);
271 if (sess->eap == NULL) {
272 RADIUS_DEBUG("Failed to initialize EAP state machine for the "
273 "new session");
274 radius_server_session_free(data, sess);
275 return NULL;
277 sess->eapRestart = TRUE;
278 sess->portEnabled = TRUE;
280 RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
282 return sess;
286 static struct radius_msg *
287 radius_server_encapsulate_eap(struct radius_server_data *data,
288 struct radius_client *client,
289 struct radius_session *sess,
290 struct radius_msg *request)
292 struct radius_msg *msg;
293 int code;
294 unsigned int sess_id;
296 if (sess->eapFail) {
297 code = RADIUS_CODE_ACCESS_REJECT;
298 } else if (sess->eapSuccess) {
299 code = RADIUS_CODE_ACCESS_ACCEPT;
300 } else {
301 code = RADIUS_CODE_ACCESS_CHALLENGE;
304 msg = radius_msg_new(code, request->hdr->identifier);
305 if (msg == NULL) {
306 return NULL;
309 sess_id = htonl(sess->sess_id);
310 if (code == RADIUS_CODE_ACCESS_CHALLENGE &&
311 !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,
312 (u8 *) &sess_id, sizeof(sess_id))) {
313 RADIUS_DEBUG("Failed to add State attribute");
316 if (sess->eapReqData &&
317 !radius_msg_add_eap(msg, sess->eapReqData, sess->eapReqDataLen)) {
318 RADIUS_DEBUG("Failed to add EAP-Message attribute");
321 if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eapKeyData) {
322 int len;
323 if (sess->eapKeyDataLen > 64) {
324 len = 32;
325 } else {
326 len = sess->eapKeyDataLen / 2;
328 if (!radius_msg_add_mppe_keys(msg, request->hdr->authenticator,
329 (u8 *) client->shared_secret,
330 client->shared_secret_len,
331 sess->eapKeyData + len, len,
332 sess->eapKeyData, len)) {
333 RADIUS_DEBUG("Failed to add MPPE key attributes");
337 if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
338 client->shared_secret_len,
339 request->hdr->authenticator) < 0) {
340 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
343 return msg;
347 static int radius_server_reject(struct radius_server_data *data,
348 struct radius_client *client,
349 struct radius_msg *request,
350 struct sockaddr *from, socklen_t fromlen,
351 const char *from_addr, int from_port)
353 struct radius_msg *msg;
354 int ret = 0;
355 struct eap_hdr eapfail;
357 RADIUS_DEBUG("Reject invalid request from %s:%d",
358 from_addr, from_port);
360 msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT,
361 request->hdr->identifier);
362 if (msg == NULL) {
363 return -1;
366 memset(&eapfail, 0, sizeof(eapfail));
367 eapfail.code = EAP_CODE_FAILURE;
368 eapfail.identifier = 0;
369 eapfail.length = htons(sizeof(eapfail));
371 if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {
372 RADIUS_DEBUG("Failed to add EAP-Message attribute");
376 if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
377 client->shared_secret_len,
378 request->hdr->authenticator) < 0) {
379 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
382 if (wpa_debug_level <= MSG_MSGDUMP) {
383 radius_msg_dump(msg);
386 if (sendto(data->auth_sock, msg->buf, msg->buf_used, 0,
387 (struct sockaddr *) from, sizeof(*from)) < 0) {
388 perror("sendto[RADIUS SRV]");
389 ret = -1;
392 radius_msg_free(msg);
393 free(msg);
395 return ret;
399 static int radius_server_request(struct radius_server_data *data,
400 struct radius_msg *msg,
401 struct sockaddr *from, socklen_t fromlen,
402 struct radius_client *client,
403 const char *from_addr, int from_port)
405 u8 *eap = NULL;
406 size_t eap_len;
407 int res, state_included = 0;
408 u8 statebuf[4], resp_id;
409 unsigned int state;
410 struct radius_session *sess;
411 struct radius_msg *reply;
412 struct eap_hdr *hdr;
414 /* TODO: Implement duplicate packet processing */
416 res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
417 sizeof(statebuf));
418 state_included = res >= 0;
419 if (res == sizeof(statebuf)) {
420 state = (statebuf[0] << 24) | (statebuf[1] << 16) |
421 (statebuf[2] << 8) | statebuf[3];
422 sess = radius_server_get_session(client, state);
423 } else {
424 sess = NULL;
427 if (sess) {
428 RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
429 } else if (state_included) {
430 RADIUS_DEBUG("State attribute included but no session found");
431 radius_server_reject(data, client, msg, from, fromlen,
432 from_addr, from_port);
433 return -1;
434 } else {
435 sess = radius_server_get_new_session(data, client, msg);
436 if (sess == NULL) {
437 RADIUS_DEBUG("Could not create a new session");
438 radius_server_reject(data, client, msg, from, fromlen,
439 from_addr, from_port);
440 return -1;
444 eap = radius_msg_get_eap(msg, &eap_len);
445 if (eap == NULL) {
446 RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
447 from_addr);
448 return -1;
451 RADIUS_DUMP("Received EAP data", eap, eap_len);
452 if (eap_len >= sizeof(*hdr)) {
453 hdr = (struct eap_hdr *) eap;
454 resp_id = hdr->identifier;
455 } else {
456 resp_id = 0;
459 /* FIX: if Code is Request, Success, or Failure, send Access-Reject;
460 * RFC3579 Sect. 2.6.2.
461 * Include EAP-Response/Nak with no preferred method if
462 * code == request.
463 * If code is not 1-4, discard the packet silently.
464 * Or is this already done by the EAP state machine? */
466 eap_set_eapRespData(sess->eap, eap, eap_len);
467 free(eap);
468 eap = NULL;
469 sess->eapResp = TRUE;
470 eap_sm_step(sess->eap);
472 if (sess->eapReqData) {
473 RADIUS_DUMP("EAP data from the state machine",
474 sess->eapReqData, sess->eapReqDataLen);
475 } else if (sess->eapFail) {
476 RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
477 "set - generate EAP-Failure");
478 hdr = malloc(sizeof(*hdr));
479 if (hdr) {
480 memset(hdr, 0, sizeof(*hdr));
481 hdr->identifier = resp_id;
482 hdr->length = htons(sizeof(*hdr));
483 sess->eapReqData = (u8 *) hdr;
484 sess->eapReqDataLen = sizeof(*hdr);
486 } else {
487 RADIUS_DEBUG("No EAP data from the state machine - ignore this"
488 " Access-Request silently (assuming it was a "
489 "duplicate)");
490 return -1;
493 reply = radius_server_encapsulate_eap(data, client, sess, msg);
495 free(sess->eapReqData);
496 sess->eapReqData = NULL;
497 sess->eapReqDataLen = 0;
499 if (reply) {
500 RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
501 if (wpa_debug_level <= MSG_MSGDUMP) {
502 radius_msg_dump(reply);
505 res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,
506 (struct sockaddr *) from, fromlen);
507 if (res < 0) {
508 perror("sendto[RADIUS SRV]");
510 radius_msg_free(reply);
511 free(reply);
514 if (sess->eapSuccess || sess->eapFail) {
515 RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
516 radius_server_session_remove(data, sess);
519 return 0;
523 static void radius_server_receive_auth(int sock, void *eloop_ctx,
524 void *sock_ctx)
526 struct radius_server_data *data = eloop_ctx;
527 u8 *buf = NULL;
528 struct sockaddr_storage from;
529 socklen_t fromlen;
530 int len;
531 struct radius_client *client = NULL;
532 struct radius_msg *msg = NULL;
533 char abuf[50];
534 int from_port = 0;
536 buf = malloc(RADIUS_MAX_MSG_LEN);
537 if (buf == NULL) {
538 goto fail;
541 fromlen = sizeof(from);
542 len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
543 (struct sockaddr *) &from, &fromlen);
544 if (len < 0) {
545 perror("recvfrom[radius_server]");
546 goto fail;
549 #ifdef CONFIG_IPV6
550 if (data->ipv6) {
551 struct sockaddr_in6 *from6 = (struct sockaddr_in6 *) &from;
552 if (inet_ntop(AF_INET6, &from6->sin6_addr, abuf, sizeof(abuf))
553 == NULL)
554 abuf[0] = '\0';
555 from_port = ntohs(from6->sin6_port);
556 RADIUS_DEBUG("Received %d bytes from %s:%d",
557 len, abuf, from_port);
559 client = radius_server_get_client(data,
560 (struct in_addr *)
561 &from6->sin6_addr, 1);
563 #endif /* CONFIG_IPV6 */
565 if (!data->ipv6) {
566 struct sockaddr_in *from4 = (struct sockaddr_in *) &from;
567 snprintf(abuf, sizeof(abuf), "%s", inet_ntoa(from4->sin_addr));
568 from_port = ntohs(from4->sin_port);
569 RADIUS_DEBUG("Received %d bytes from %s:%d",
570 len, abuf, from_port);
572 client = radius_server_get_client(data, &from4->sin_addr, 0);
575 RADIUS_DUMP("Received data", buf, len);
577 if (client == NULL) {
578 RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
579 goto fail;
582 msg = radius_msg_parse(buf, len);
583 if (msg == NULL) {
584 RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
585 goto fail;
588 free(buf);
589 buf = NULL;
591 if (wpa_debug_level <= MSG_MSGDUMP) {
592 radius_msg_dump(msg);
595 if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) {
596 RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code);
597 goto fail;
600 if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
601 client->shared_secret_len, NULL)) {
602 RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
603 goto fail;
606 radius_server_request(data, msg, (struct sockaddr *) &from, fromlen,
607 client, abuf, from_port);
609 fail:
610 if (msg) {
611 radius_msg_free(msg);
612 free(msg);
614 free(buf);
618 static int radius_server_open_socket(int port)
620 int s;
621 struct sockaddr_in addr;
623 s = socket(PF_INET, SOCK_DGRAM, 0);
624 if (s < 0) {
625 perror("socket");
626 return -1;
629 memset(&addr, 0, sizeof(addr));
630 addr.sin_family = AF_INET;
631 addr.sin_port = htons(port);
632 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
633 perror("bind");
634 close(s);
635 return -1;
638 return s;
642 #ifdef CONFIG_IPV6
643 static int radius_server_open_socket6(int port)
645 int s;
646 struct sockaddr_in6 addr;
648 s = socket(PF_INET6, SOCK_DGRAM, 0);
649 if (s < 0) {
650 perror("socket[IPv6]");
651 return -1;
654 memset(&addr, 0, sizeof(addr));
655 addr.sin6_family = AF_INET6;
656 memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
657 addr.sin6_port = htons(port);
658 if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
659 perror("bind");
660 close(s);
661 return -1;
664 return s;
666 #endif /* CONFIG_IPV6 */
669 static void radius_server_free_sessions(struct radius_server_data *data,
670 struct radius_session *sessions)
672 struct radius_session *session, *prev;
674 session = sessions;
675 while (session) {
676 prev = session;
677 session = session->next;
678 radius_server_session_free(data, prev);
683 static void radius_server_free_clients(struct radius_server_data *data,
684 struct radius_client *clients)
686 struct radius_client *client, *prev;
688 client = clients;
689 while (client) {
690 prev = client;
691 client = client->next;
693 radius_server_free_sessions(data, prev->sessions);
694 free(prev->shared_secret);
695 free(prev);
700 static struct radius_client *
701 radius_server_read_clients(const char *client_file, int ipv6)
703 FILE *f;
704 const int buf_size = 1024;
705 char *buf, *pos;
706 struct radius_client *clients, *tail, *entry;
707 int line = 0, mask, failed = 0, i;
708 struct in_addr addr;
709 #ifdef CONFIG_IPV6
710 struct in6_addr addr6;
711 #endif /* CONFIG_IPV6 */
712 unsigned int val;
714 f = fopen(client_file, "r");
715 if (f == NULL) {
716 RADIUS_ERROR("Could not open client file '%s'", client_file);
717 return NULL;
720 buf = malloc(buf_size);
721 if (buf == NULL) {
722 fclose(f);
723 return NULL;
726 clients = tail = NULL;
727 while (fgets(buf, buf_size, f)) {
728 /* Configuration file format:
729 * 192.168.1.0/24 secret
730 * 192.168.1.2 secret
731 * fe80::211:22ff:fe33:4455/64 secretipv6
733 line++;
734 buf[buf_size - 1] = '\0';
735 pos = buf;
736 while (*pos != '\0' && *pos != '\n')
737 pos++;
738 if (*pos == '\n')
739 *pos = '\0';
740 if (*buf == '\0' || *buf == '#')
741 continue;
743 pos = buf;
744 while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
745 (*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
746 (*pos >= 'A' && *pos <= 'F')) {
747 pos++;
750 if (*pos == '\0') {
751 failed = 1;
752 break;
755 if (*pos == '/') {
756 char *end;
757 *pos++ = '\0';
758 mask = strtol(pos, &end, 10);
759 if ((pos == end) ||
760 (mask < 0 || mask > (ipv6 ? 128 : 32))) {
761 failed = 1;
762 break;
764 pos = end;
765 } else {
766 mask = ipv6 ? 128 : 32;
767 *pos++ = '\0';
770 if (!ipv6 && inet_aton(buf, &addr) == 0) {
771 failed = 1;
772 break;
774 #ifdef CONFIG_IPV6
775 if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
776 if (inet_pton(AF_INET, buf, &addr) <= 0) {
777 failed = 1;
778 break;
780 /* Convert IPv4 address to IPv6 */
781 if (mask <= 32)
782 mask += (128 - 32);
783 memset(addr6.s6_addr, 0, 10);
784 addr6.s6_addr[10] = 0xff;
785 addr6.s6_addr[11] = 0xff;
786 memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr, 4);
788 #endif /* CONFIG_IPV6 */
790 while (*pos == ' ' || *pos == '\t') {
791 pos++;
794 if (*pos == '\0') {
795 failed = 1;
796 break;
799 entry = malloc(sizeof(*entry));
800 if (entry == NULL) {
801 failed = 1;
802 break;
804 memset(entry, 0, sizeof(*entry));
805 entry->shared_secret = strdup(pos);
806 if (entry->shared_secret == NULL) {
807 failed = 1;
808 free(entry);
809 break;
811 entry->shared_secret_len = strlen(entry->shared_secret);
812 entry->addr.s_addr = addr.s_addr;
813 if (!ipv6) {
814 val = 0;
815 for (i = 0; i < mask; i++)
816 val |= 1 << (31 - i);
817 entry->mask.s_addr = htonl(val);
819 #ifdef CONFIG_IPV6
820 if (ipv6) {
821 int offset = mask / 8;
823 memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
824 memset(entry->mask6.s6_addr, 0xff, offset);
825 val = 0;
826 for (i = 0; i < (mask % 8); i++)
827 val |= 1 << (7 - i);
828 if (offset < 16)
829 entry->mask6.s6_addr[offset] = val;
831 #endif /* CONFIG_IPV6 */
833 if (tail == NULL) {
834 clients = tail = entry;
835 } else {
836 tail->next = entry;
837 tail = entry;
841 if (failed) {
842 RADIUS_ERROR("Invalid line %d in '%s'", line, client_file);
843 radius_server_free_clients(NULL, clients);
844 clients = NULL;
847 free(buf);
848 fclose(f);
850 return clients;
854 struct radius_server_data *
855 radius_server_init(struct radius_server_conf *conf)
857 struct radius_server_data *data;
859 #ifndef CONFIG_IPV6
860 if (conf->ipv6) {
861 fprintf(stderr, "RADIUS server compiled without IPv6 "
862 "support.\n");
863 return NULL;
865 #endif /* CONFIG_IPV6 */
867 data = malloc(sizeof(*data));
868 if (data == NULL) {
869 return NULL;
871 memset(data, 0, sizeof(*data));
872 data->hostapd_conf = conf->hostapd_conf;
873 data->eap_sim_db_priv = conf->eap_sim_db_priv;
874 data->ssl_ctx = conf->ssl_ctx;
875 data->ipv6 = conf->ipv6;
877 data->clients = radius_server_read_clients(conf->client_file,
878 conf->ipv6);
879 if (data->clients == NULL) {
880 printf("No RADIUS clients configured.\n");
881 radius_server_deinit(data);
882 return NULL;
885 #ifdef CONFIG_IPV6
886 if (conf->ipv6)
887 data->auth_sock = radius_server_open_socket6(conf->auth_port);
888 else
889 #endif /* CONFIG_IPV6 */
890 data->auth_sock = radius_server_open_socket(conf->auth_port);
891 if (data->auth_sock < 0) {
892 printf("Failed to open UDP socket for RADIUS authentication "
893 "server\n");
894 radius_server_deinit(data);
895 return NULL;
897 if (eloop_register_read_sock(data->auth_sock,
898 radius_server_receive_auth,
899 data, NULL)) {
900 radius_server_deinit(data);
901 return NULL;
904 return data;
908 void radius_server_deinit(struct radius_server_data *data)
910 if (data == NULL)
911 return;
913 if (data->auth_sock >= 0) {
914 eloop_unregister_read_sock(data->auth_sock);
915 close(data->auth_sock);
918 radius_server_free_clients(data, data->clients);
920 free(data);
924 int radius_server_get_mib(struct radius_server_data *data, char *buf,
925 size_t buflen)
927 /* TODO: add support for RADIUS authentication server MIB */
928 return 0;
932 static Boolean radius_server_get_bool(void *ctx, enum eapol_bool_var variable)
934 struct radius_session *sess = ctx;
935 if (sess == NULL)
936 return FALSE;
937 switch (variable) {
938 case EAPOL_eapSuccess:
939 return sess->eapSuccess;
940 case EAPOL_eapRestart:
941 return sess->eapRestart;
942 case EAPOL_eapFail:
943 return sess->eapFail;
944 case EAPOL_eapResp:
945 return sess->eapResp;
946 case EAPOL_eapReq:
947 return sess->eapReq;
948 case EAPOL_eapNoReq:
949 return sess->eapNoReq;
950 case EAPOL_portEnabled:
951 return sess->portEnabled;
952 case EAPOL_eapTimeout:
953 return sess->eapTimeout;
955 return FALSE;
959 static void radius_server_set_bool(void *ctx, enum eapol_bool_var variable,
960 Boolean value)
962 struct radius_session *sess = ctx;
963 if (sess == NULL)
964 return;
965 switch (variable) {
966 case EAPOL_eapSuccess:
967 sess->eapSuccess = value;
968 break;
969 case EAPOL_eapRestart:
970 sess->eapRestart = value;
971 break;
972 case EAPOL_eapFail:
973 sess->eapFail = value;
974 break;
975 case EAPOL_eapResp:
976 sess->eapResp = value;
977 break;
978 case EAPOL_eapReq:
979 sess->eapReq = value;
980 break;
981 case EAPOL_eapNoReq:
982 sess->eapNoReq = value;
983 break;
984 case EAPOL_portEnabled:
985 sess->portEnabled = value;
986 break;
987 case EAPOL_eapTimeout:
988 sess->eapTimeout = value;
989 break;
994 static void radius_server_set_eapReqData(void *ctx, const u8 *eapReqData,
995 size_t eapReqDataLen)
997 struct radius_session *sess = ctx;
998 if (sess == NULL)
999 return;
1001 free(sess->eapReqData);
1002 sess->eapReqData = malloc(eapReqDataLen);
1003 if (sess->eapReqData) {
1004 memcpy(sess->eapReqData, eapReqData, eapReqDataLen);
1005 sess->eapReqDataLen = eapReqDataLen;
1006 } else {
1007 sess->eapReqDataLen = 0;
1012 static void radius_server_set_eapKeyData(void *ctx, const u8 *eapKeyData,
1013 size_t eapKeyDataLen)
1015 struct radius_session *sess = ctx;
1017 if (sess == NULL)
1018 return;
1020 free(sess->eapKeyData);
1021 if (eapKeyData) {
1022 sess->eapKeyData = malloc(eapKeyDataLen);
1023 if (sess->eapKeyData) {
1024 memcpy(sess->eapKeyData, eapKeyData, eapKeyDataLen);
1025 sess->eapKeyDataLen = eapKeyDataLen;
1026 } else {
1027 sess->eapKeyDataLen = 0;
1029 } else {
1030 sess->eapKeyData = NULL;
1031 sess->eapKeyDataLen = 0;
1036 static int radius_server_get_eap_user(void *ctx, const u8 *identity,
1037 size_t identity_len, int phase2,
1038 struct eap_user *user)
1040 struct radius_session *sess = ctx;
1041 const struct hostapd_eap_user *eap_user;
1043 eap_user = hostapd_get_eap_user(sess->server->hostapd_conf, identity,
1044 identity_len, phase2);
1045 if (eap_user == NULL)
1046 return -1;
1048 memset(user, 0, sizeof(*user));
1049 memcpy(user->methods, eap_user->methods,
1050 EAP_USER_MAX_METHODS > EAP_MAX_METHODS ?
1051 EAP_USER_MAX_METHODS : EAP_MAX_METHODS);
1053 if (eap_user->password) {
1054 user->password = malloc(eap_user->password_len);
1055 if (user->password == NULL)
1056 return -1;
1057 memcpy(user->password, eap_user->password,
1058 eap_user->password_len);
1059 user->password_len = eap_user->password_len;
1061 user->force_version = eap_user->force_version;
1063 return 0;
1067 static struct eapol_callbacks radius_server_eapol_cb =
1069 .get_bool = radius_server_get_bool,
1070 .set_bool = radius_server_set_bool,
1071 .set_eapReqData = radius_server_set_eapReqData,
1072 .set_eapKeyData = radius_server_set_eapKeyData,
1073 .get_eap_user = radius_server_get_eap_user,