2 * hostapd / RADIUS authentication server
3 * Copyright (c) 2005-2008, Jouni Malinen <j@w1.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
12 * See README and COPYING for more details.
22 #include "eap_server/eap.h"
23 #include "radius_server.h"
25 #define RADIUS_SESSION_TIMEOUT 60
26 #define RADIUS_MAX_SESSION 100
27 #define RADIUS_MAX_MSG_LEN 3000
29 static struct eapol_callbacks radius_server_eapol_cb
;
32 struct radius_server_data
;
34 struct radius_server_counters
{
37 u32 dup_access_requests
;
40 u32 access_challenges
;
41 u32 malformed_access_requests
;
42 u32 bad_authenticators
;
47 struct radius_session
{
48 struct radius_session
*next
;
49 struct radius_client
*client
;
50 struct radius_server_data
*server
;
53 struct eap_eapol_interface
*eap_if
;
55 struct radius_msg
*last_msg
;
58 struct sockaddr_storage last_from
;
59 socklen_t last_fromlen
;
61 struct radius_msg
*last_reply
;
62 u8 last_authenticator
[16];
65 struct radius_client
{
66 struct radius_client
*next
;
70 struct in6_addr addr6
;
71 struct in6_addr mask6
;
72 #endif /* CONFIG_IPV6 */
74 int shared_secret_len
;
75 struct radius_session
*sessions
;
76 struct radius_server_counters counters
;
79 struct radius_server_data
{
81 struct radius_client
*clients
;
82 unsigned int next_sess_id
;
85 void *eap_sim_db_priv
;
87 u8
*pac_opaque_encr_key
;
89 size_t eap_fast_a_id_len
;
90 char *eap_fast_a_id_info
;
93 int pac_key_refresh_time
;
94 int eap_sim_aka_result_ind
;
96 struct wps_context
*wps
;
98 struct os_time start_time
;
99 struct radius_server_counters counters
;
100 int (*get_eap_user
)(void *ctx
, const u8
*identity
, size_t identity_len
,
101 int phase2
, struct eap_user
*user
);
102 char *eap_req_id_text
;
103 size_t eap_req_id_text_len
;
107 extern int wpa_debug_level
;
109 #define RADIUS_DEBUG(args...) \
110 wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
111 #define RADIUS_ERROR(args...) \
112 wpa_printf(MSG_ERROR, "RADIUS SRV: " args)
113 #define RADIUS_DUMP(args...) \
114 wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
115 #define RADIUS_DUMP_ASCII(args...) \
116 wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
119 static void radius_server_session_timeout(void *eloop_ctx
, void *timeout_ctx
);
120 static void radius_server_session_remove_timeout(void *eloop_ctx
,
124 static struct radius_client
*
125 radius_server_get_client(struct radius_server_data
*data
, struct in_addr
*addr
,
128 struct radius_client
*client
= data
->clients
;
133 struct in6_addr
*addr6
;
136 addr6
= (struct in6_addr
*) addr
;
137 for (i
= 0; i
< 16; i
++) {
138 if ((addr6
->s6_addr
[i
] &
139 client
->mask6
.s6_addr
[i
]) !=
140 (client
->addr6
.s6_addr
[i
] &
141 client
->mask6
.s6_addr
[i
])) {
150 #endif /* CONFIG_IPV6 */
151 if (!ipv6
&& (client
->addr
.s_addr
& client
->mask
.s_addr
) ==
152 (addr
->s_addr
& client
->mask
.s_addr
)) {
156 client
= client
->next
;
163 static struct radius_session
*
164 radius_server_get_session(struct radius_client
*client
, unsigned int sess_id
)
166 struct radius_session
*sess
= client
->sessions
;
169 if (sess
->sess_id
== sess_id
) {
179 static void radius_server_session_free(struct radius_server_data
*data
,
180 struct radius_session
*sess
)
182 eloop_cancel_timeout(radius_server_session_timeout
, data
, sess
);
183 eloop_cancel_timeout(radius_server_session_remove_timeout
, data
, sess
);
184 eap_server_sm_deinit(sess
->eap
);
185 if (sess
->last_msg
) {
186 radius_msg_free(sess
->last_msg
);
187 os_free(sess
->last_msg
);
189 os_free(sess
->last_from_addr
);
190 if (sess
->last_reply
) {
191 radius_msg_free(sess
->last_reply
);
192 os_free(sess
->last_reply
);
199 static void radius_server_session_remove(struct radius_server_data
*data
,
200 struct radius_session
*sess
)
202 struct radius_client
*client
= sess
->client
;
203 struct radius_session
*session
, *prev
;
205 eloop_cancel_timeout(radius_server_session_remove_timeout
, data
, sess
);
208 session
= client
->sessions
;
210 if (session
== sess
) {
212 client
->sessions
= sess
->next
;
214 prev
->next
= sess
->next
;
216 radius_server_session_free(data
, sess
);
220 session
= session
->next
;
225 static void radius_server_session_remove_timeout(void *eloop_ctx
,
228 struct radius_server_data
*data
= eloop_ctx
;
229 struct radius_session
*sess
= timeout_ctx
;
230 RADIUS_DEBUG("Removing completed session 0x%x", sess
->sess_id
);
231 radius_server_session_remove(data
, sess
);
235 static void radius_server_session_timeout(void *eloop_ctx
, void *timeout_ctx
)
237 struct radius_server_data
*data
= eloop_ctx
;
238 struct radius_session
*sess
= timeout_ctx
;
240 RADIUS_DEBUG("Timing out authentication session 0x%x", sess
->sess_id
);
241 radius_server_session_remove(data
, sess
);
245 static struct radius_session
*
246 radius_server_new_session(struct radius_server_data
*data
,
247 struct radius_client
*client
)
249 struct radius_session
*sess
;
251 if (data
->num_sess
>= RADIUS_MAX_SESSION
) {
252 RADIUS_DEBUG("Maximum number of existing session - no room "
253 "for a new session");
257 sess
= os_zalloc(sizeof(*sess
));
262 sess
->client
= client
;
263 sess
->sess_id
= data
->next_sess_id
++;
264 sess
->next
= client
->sessions
;
265 client
->sessions
= sess
;
266 eloop_register_timeout(RADIUS_SESSION_TIMEOUT
, 0,
267 radius_server_session_timeout
, data
, sess
);
273 static struct radius_session
*
274 radius_server_get_new_session(struct radius_server_data
*data
,
275 struct radius_client
*client
,
276 struct radius_msg
*msg
)
281 struct radius_session
*sess
;
282 struct eap_config eap_conf
;
284 RADIUS_DEBUG("Creating a new session");
286 user
= os_malloc(256);
290 res
= radius_msg_get_attr(msg
, RADIUS_ATTR_USER_NAME
, user
, 256);
291 if (res
< 0 || res
> 256) {
292 RADIUS_DEBUG("Could not get User-Name");
297 RADIUS_DUMP_ASCII("User-Name", user
, user_len
);
299 res
= data
->get_eap_user(data
->conf_ctx
, user
, user_len
, 0, NULL
);
303 RADIUS_DEBUG("Matching user entry found");
304 sess
= radius_server_new_session(data
, client
);
306 RADIUS_DEBUG("Failed to create a new session");
310 RADIUS_DEBUG("User-Name not found from user database");
314 os_memset(&eap_conf
, 0, sizeof(eap_conf
));
315 eap_conf
.ssl_ctx
= data
->ssl_ctx
;
316 eap_conf
.eap_sim_db_priv
= data
->eap_sim_db_priv
;
317 eap_conf
.backend_auth
= TRUE
;
318 eap_conf
.eap_server
= 1;
319 eap_conf
.pac_opaque_encr_key
= data
->pac_opaque_encr_key
;
320 eap_conf
.eap_fast_a_id
= data
->eap_fast_a_id
;
321 eap_conf
.eap_fast_a_id_len
= data
->eap_fast_a_id_len
;
322 eap_conf
.eap_fast_a_id_info
= data
->eap_fast_a_id_info
;
323 eap_conf
.eap_fast_prov
= data
->eap_fast_prov
;
324 eap_conf
.pac_key_lifetime
= data
->pac_key_lifetime
;
325 eap_conf
.pac_key_refresh_time
= data
->pac_key_refresh_time
;
326 eap_conf
.eap_sim_aka_result_ind
= data
->eap_sim_aka_result_ind
;
327 eap_conf
.tnc
= data
->tnc
;
328 eap_conf
.wps
= data
->wps
;
329 sess
->eap
= eap_server_sm_init(sess
, &radius_server_eapol_cb
,
331 if (sess
->eap
== NULL
) {
332 RADIUS_DEBUG("Failed to initialize EAP state machine for the "
334 radius_server_session_free(data
, sess
);
337 sess
->eap_if
= eap_get_interface(sess
->eap
);
338 sess
->eap_if
->eapRestart
= TRUE
;
339 sess
->eap_if
->portEnabled
= TRUE
;
341 RADIUS_DEBUG("New session 0x%x initialized", sess
->sess_id
);
347 static struct radius_msg
*
348 radius_server_encapsulate_eap(struct radius_server_data
*data
,
349 struct radius_client
*client
,
350 struct radius_session
*sess
,
351 struct radius_msg
*request
)
353 struct radius_msg
*msg
;
355 unsigned int sess_id
;
357 if (sess
->eap_if
->eapFail
) {
358 sess
->eap_if
->eapFail
= FALSE
;
359 code
= RADIUS_CODE_ACCESS_REJECT
;
360 } else if (sess
->eap_if
->eapSuccess
) {
361 sess
->eap_if
->eapSuccess
= FALSE
;
362 code
= RADIUS_CODE_ACCESS_ACCEPT
;
364 sess
->eap_if
->eapReq
= FALSE
;
365 code
= RADIUS_CODE_ACCESS_CHALLENGE
;
368 msg
= radius_msg_new(code
, request
->hdr
->identifier
);
370 RADIUS_DEBUG("Failed to allocate reply message");
374 sess_id
= htonl(sess
->sess_id
);
375 if (code
== RADIUS_CODE_ACCESS_CHALLENGE
&&
376 !radius_msg_add_attr(msg
, RADIUS_ATTR_STATE
,
377 (u8
*) &sess_id
, sizeof(sess_id
))) {
378 RADIUS_DEBUG("Failed to add State attribute");
381 if (sess
->eap_if
->eapReqData
&&
382 !radius_msg_add_eap(msg
, wpabuf_head(sess
->eap_if
->eapReqData
),
383 wpabuf_len(sess
->eap_if
->eapReqData
))) {
384 RADIUS_DEBUG("Failed to add EAP-Message attribute");
387 if (code
== RADIUS_CODE_ACCESS_ACCEPT
&& sess
->eap_if
->eapKeyData
) {
389 if (sess
->eap_if
->eapKeyDataLen
> 64) {
392 len
= sess
->eap_if
->eapKeyDataLen
/ 2;
394 if (!radius_msg_add_mppe_keys(msg
, request
->hdr
->authenticator
,
395 (u8
*) client
->shared_secret
,
396 client
->shared_secret_len
,
397 sess
->eap_if
->eapKeyData
+ len
,
398 len
, sess
->eap_if
->eapKeyData
,
400 RADIUS_DEBUG("Failed to add MPPE key attributes");
404 if (radius_msg_copy_attr(msg
, request
, RADIUS_ATTR_PROXY_STATE
) < 0) {
405 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
406 radius_msg_free(msg
);
411 if (radius_msg_finish_srv(msg
, (u8
*) client
->shared_secret
,
412 client
->shared_secret_len
,
413 request
->hdr
->authenticator
) < 0) {
414 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
421 static int radius_server_reject(struct radius_server_data
*data
,
422 struct radius_client
*client
,
423 struct radius_msg
*request
,
424 struct sockaddr
*from
, socklen_t fromlen
,
425 const char *from_addr
, int from_port
)
427 struct radius_msg
*msg
;
429 struct eap_hdr eapfail
;
431 RADIUS_DEBUG("Reject invalid request from %s:%d",
432 from_addr
, from_port
);
434 msg
= radius_msg_new(RADIUS_CODE_ACCESS_REJECT
,
435 request
->hdr
->identifier
);
440 os_memset(&eapfail
, 0, sizeof(eapfail
));
441 eapfail
.code
= EAP_CODE_FAILURE
;
442 eapfail
.identifier
= 0;
443 eapfail
.length
= host_to_be16(sizeof(eapfail
));
445 if (!radius_msg_add_eap(msg
, (u8
*) &eapfail
, sizeof(eapfail
))) {
446 RADIUS_DEBUG("Failed to add EAP-Message attribute");
449 if (radius_msg_copy_attr(msg
, request
, RADIUS_ATTR_PROXY_STATE
) < 0) {
450 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
451 radius_msg_free(msg
);
456 if (radius_msg_finish_srv(msg
, (u8
*) client
->shared_secret
,
457 client
->shared_secret_len
,
458 request
->hdr
->authenticator
) < 0) {
459 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
462 if (wpa_debug_level
<= MSG_MSGDUMP
) {
463 radius_msg_dump(msg
);
466 data
->counters
.access_rejects
++;
467 client
->counters
.access_rejects
++;
468 if (sendto(data
->auth_sock
, msg
->buf
, msg
->buf_used
, 0,
469 (struct sockaddr
*) from
, sizeof(*from
)) < 0) {
470 perror("sendto[RADIUS SRV]");
474 radius_msg_free(msg
);
481 static int radius_server_request(struct radius_server_data
*data
,
482 struct radius_msg
*msg
,
483 struct sockaddr
*from
, socklen_t fromlen
,
484 struct radius_client
*client
,
485 const char *from_addr
, int from_port
,
486 struct radius_session
*force_sess
)
490 int res
, state_included
= 0;
493 struct radius_session
*sess
;
494 struct radius_msg
*reply
;
500 res
= radius_msg_get_attr(msg
, RADIUS_ATTR_STATE
, statebuf
,
502 state_included
= res
>= 0;
503 if (res
== sizeof(statebuf
)) {
504 state
= WPA_GET_BE32(statebuf
);
505 sess
= radius_server_get_session(client
, state
);
512 RADIUS_DEBUG("Request for session 0x%x", sess
->sess_id
);
513 } else if (state_included
) {
514 RADIUS_DEBUG("State attribute included but no session found");
515 radius_server_reject(data
, client
, msg
, from
, fromlen
,
516 from_addr
, from_port
);
519 sess
= radius_server_get_new_session(data
, client
, msg
);
521 RADIUS_DEBUG("Could not create a new session");
522 radius_server_reject(data
, client
, msg
, from
, fromlen
,
523 from_addr
, from_port
);
528 if (sess
->last_from_port
== from_port
&&
529 sess
->last_identifier
== msg
->hdr
->identifier
&&
530 os_memcmp(sess
->last_authenticator
, msg
->hdr
->authenticator
, 16) ==
532 RADIUS_DEBUG("Duplicate message from %s", from_addr
);
533 data
->counters
.dup_access_requests
++;
534 client
->counters
.dup_access_requests
++;
536 if (sess
->last_reply
) {
537 res
= sendto(data
->auth_sock
, sess
->last_reply
->buf
,
538 sess
->last_reply
->buf_used
, 0,
539 (struct sockaddr
*) from
, fromlen
);
541 perror("sendto[RADIUS SRV]");
546 RADIUS_DEBUG("No previous reply available for duplicate "
551 eap
= radius_msg_get_eap(msg
, &eap_len
);
553 RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
555 data
->counters
.packets_dropped
++;
556 client
->counters
.packets_dropped
++;
560 RADIUS_DUMP("Received EAP data", eap
, eap_len
);
562 /* FIX: if Code is Request, Success, or Failure, send Access-Reject;
563 * RFC3579 Sect. 2.6.2.
564 * Include EAP-Response/Nak with no preferred method if
566 * If code is not 1-4, discard the packet silently.
567 * Or is this already done by the EAP state machine? */
569 wpabuf_free(sess
->eap_if
->eapRespData
);
570 sess
->eap_if
->eapRespData
= wpabuf_alloc_ext_data(eap
, eap_len
);
571 if (sess
->eap_if
->eapRespData
== NULL
)
574 sess
->eap_if
->eapResp
= TRUE
;
575 eap_server_sm_step(sess
->eap
);
577 if ((sess
->eap_if
->eapReq
|| sess
->eap_if
->eapSuccess
||
578 sess
->eap_if
->eapFail
) && sess
->eap_if
->eapReqData
) {
579 RADIUS_DUMP("EAP data from the state machine",
580 wpabuf_head(sess
->eap_if
->eapReqData
),
581 wpabuf_len(sess
->eap_if
->eapReqData
));
582 } else if (sess
->eap_if
->eapFail
) {
583 RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
585 } else if (eap_sm_method_pending(sess
->eap
)) {
586 if (sess
->last_msg
) {
587 radius_msg_free(sess
->last_msg
);
588 os_free(sess
->last_msg
);
590 sess
->last_msg
= msg
;
591 sess
->last_from_port
= from_port
;
592 os_free(sess
->last_from_addr
);
593 sess
->last_from_addr
= os_strdup(from_addr
);
594 sess
->last_fromlen
= fromlen
;
595 os_memcpy(&sess
->last_from
, from
, fromlen
);
598 RADIUS_DEBUG("No EAP data from the state machine - ignore this"
599 " Access-Request silently (assuming it was a "
601 data
->counters
.packets_dropped
++;
602 client
->counters
.packets_dropped
++;
606 if (sess
->eap_if
->eapSuccess
|| sess
->eap_if
->eapFail
)
609 reply
= radius_server_encapsulate_eap(data
, client
, sess
, msg
);
612 RADIUS_DEBUG("Reply to %s:%d", from_addr
, from_port
);
613 if (wpa_debug_level
<= MSG_MSGDUMP
) {
614 radius_msg_dump(reply
);
617 switch (reply
->hdr
->code
) {
618 case RADIUS_CODE_ACCESS_ACCEPT
:
619 data
->counters
.access_accepts
++;
620 client
->counters
.access_accepts
++;
622 case RADIUS_CODE_ACCESS_REJECT
:
623 data
->counters
.access_rejects
++;
624 client
->counters
.access_rejects
++;
626 case RADIUS_CODE_ACCESS_CHALLENGE
:
627 data
->counters
.access_challenges
++;
628 client
->counters
.access_challenges
++;
631 res
= sendto(data
->auth_sock
, reply
->buf
, reply
->buf_used
, 0,
632 (struct sockaddr
*) from
, fromlen
);
634 perror("sendto[RADIUS SRV]");
636 if (sess
->last_reply
) {
637 radius_msg_free(sess
->last_reply
);
638 os_free(sess
->last_reply
);
640 sess
->last_reply
= reply
;
641 sess
->last_from_port
= from_port
;
642 sess
->last_identifier
= msg
->hdr
->identifier
;
643 os_memcpy(sess
->last_authenticator
, msg
->hdr
->authenticator
,
646 data
->counters
.packets_dropped
++;
647 client
->counters
.packets_dropped
++;
651 RADIUS_DEBUG("Removing completed session 0x%x after timeout",
653 eloop_cancel_timeout(radius_server_session_remove_timeout
,
655 eloop_register_timeout(10, 0,
656 radius_server_session_remove_timeout
,
664 static void radius_server_receive_auth(int sock
, void *eloop_ctx
,
667 struct radius_server_data
*data
= eloop_ctx
;
670 struct sockaddr_storage ss
;
671 struct sockaddr_in sin
;
673 struct sockaddr_in6 sin6
;
674 #endif /* CONFIG_IPV6 */
678 struct radius_client
*client
= NULL
;
679 struct radius_msg
*msg
= NULL
;
683 buf
= os_malloc(RADIUS_MAX_MSG_LEN
);
688 fromlen
= sizeof(from
);
689 len
= recvfrom(sock
, buf
, RADIUS_MAX_MSG_LEN
, 0,
690 (struct sockaddr
*) &from
.ss
, &fromlen
);
692 perror("recvfrom[radius_server]");
698 if (inet_ntop(AF_INET6
, &from
.sin6
.sin6_addr
, abuf
,
699 sizeof(abuf
)) == NULL
)
701 from_port
= ntohs(from
.sin6
.sin6_port
);
702 RADIUS_DEBUG("Received %d bytes from %s:%d",
703 len
, abuf
, from_port
);
705 client
= radius_server_get_client(data
,
707 &from
.sin6
.sin6_addr
, 1);
709 #endif /* CONFIG_IPV6 */
712 os_strlcpy(abuf
, inet_ntoa(from
.sin
.sin_addr
), sizeof(abuf
));
713 from_port
= ntohs(from
.sin
.sin_port
);
714 RADIUS_DEBUG("Received %d bytes from %s:%d",
715 len
, abuf
, from_port
);
717 client
= radius_server_get_client(data
, &from
.sin
.sin_addr
, 0);
720 RADIUS_DUMP("Received data", buf
, len
);
722 if (client
== NULL
) {
723 RADIUS_DEBUG("Unknown client %s - packet ignored", abuf
);
724 data
->counters
.invalid_requests
++;
728 msg
= radius_msg_parse(buf
, len
);
730 RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
731 data
->counters
.malformed_access_requests
++;
732 client
->counters
.malformed_access_requests
++;
739 if (wpa_debug_level
<= MSG_MSGDUMP
) {
740 radius_msg_dump(msg
);
743 if (msg
->hdr
->code
!= RADIUS_CODE_ACCESS_REQUEST
) {
744 RADIUS_DEBUG("Unexpected RADIUS code %d", msg
->hdr
->code
);
745 data
->counters
.unknown_types
++;
746 client
->counters
.unknown_types
++;
750 data
->counters
.access_requests
++;
751 client
->counters
.access_requests
++;
753 if (radius_msg_verify_msg_auth(msg
, (u8
*) client
->shared_secret
,
754 client
->shared_secret_len
, NULL
)) {
755 RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf
);
756 data
->counters
.bad_authenticators
++;
757 client
->counters
.bad_authenticators
++;
761 if (radius_server_request(data
, msg
, (struct sockaddr
*) &from
,
762 fromlen
, client
, abuf
, from_port
, NULL
) ==
764 return; /* msg was stored with the session */
768 radius_msg_free(msg
);
775 static int radius_server_disable_pmtu_discovery(int s
)
778 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
779 /* Turn off Path MTU discovery on IPv4/UDP sockets. */
780 int action
= IP_PMTUDISC_DONT
;
781 r
= setsockopt(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, &action
,
784 wpa_printf(MSG_ERROR
, "Failed to set IP_MTU_DISCOVER: "
785 "%s", strerror(errno
));
791 static int radius_server_open_socket(int port
)
794 struct sockaddr_in addr
;
796 s
= socket(PF_INET
, SOCK_DGRAM
, 0);
802 radius_server_disable_pmtu_discovery(s
);
804 os_memset(&addr
, 0, sizeof(addr
));
805 addr
.sin_family
= AF_INET
;
806 addr
.sin_port
= htons(port
);
807 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
818 static int radius_server_open_socket6(int port
)
821 struct sockaddr_in6 addr
;
823 s
= socket(PF_INET6
, SOCK_DGRAM
, 0);
825 perror("socket[IPv6]");
829 os_memset(&addr
, 0, sizeof(addr
));
830 addr
.sin6_family
= AF_INET6
;
831 os_memcpy(&addr
.sin6_addr
, &in6addr_any
, sizeof(in6addr_any
));
832 addr
.sin6_port
= htons(port
);
833 if (bind(s
, (struct sockaddr
*) &addr
, sizeof(addr
)) < 0) {
841 #endif /* CONFIG_IPV6 */
844 static void radius_server_free_sessions(struct radius_server_data
*data
,
845 struct radius_session
*sessions
)
847 struct radius_session
*session
, *prev
;
852 session
= session
->next
;
853 radius_server_session_free(data
, prev
);
858 static void radius_server_free_clients(struct radius_server_data
*data
,
859 struct radius_client
*clients
)
861 struct radius_client
*client
, *prev
;
866 client
= client
->next
;
868 radius_server_free_sessions(data
, prev
->sessions
);
869 os_free(prev
->shared_secret
);
875 static struct radius_client
*
876 radius_server_read_clients(const char *client_file
, int ipv6
)
879 const int buf_size
= 1024;
881 struct radius_client
*clients
, *tail
, *entry
;
882 int line
= 0, mask
, failed
= 0, i
;
885 struct in6_addr addr6
;
886 #endif /* CONFIG_IPV6 */
889 f
= fopen(client_file
, "r");
891 RADIUS_ERROR("Could not open client file '%s'", client_file
);
895 buf
= os_malloc(buf_size
);
901 clients
= tail
= NULL
;
902 while (fgets(buf
, buf_size
, f
)) {
903 /* Configuration file format:
904 * 192.168.1.0/24 secret
906 * fe80::211:22ff:fe33:4455/64 secretipv6
909 buf
[buf_size
- 1] = '\0';
911 while (*pos
!= '\0' && *pos
!= '\n')
915 if (*buf
== '\0' || *buf
== '#')
919 while ((*pos
>= '0' && *pos
<= '9') || *pos
== '.' ||
920 (*pos
>= 'a' && *pos
<= 'f') || *pos
== ':' ||
921 (*pos
>= 'A' && *pos
<= 'F')) {
933 mask
= strtol(pos
, &end
, 10);
935 (mask
< 0 || mask
> (ipv6
? 128 : 32))) {
941 mask
= ipv6
? 128 : 32;
945 if (!ipv6
&& inet_aton(buf
, &addr
) == 0) {
950 if (ipv6
&& inet_pton(AF_INET6
, buf
, &addr6
) <= 0) {
951 if (inet_pton(AF_INET
, buf
, &addr
) <= 0) {
955 /* Convert IPv4 address to IPv6 */
958 os_memset(addr6
.s6_addr
, 0, 10);
959 addr6
.s6_addr
[10] = 0xff;
960 addr6
.s6_addr
[11] = 0xff;
961 os_memcpy(addr6
.s6_addr
+ 12, (char *) &addr
.s_addr
,
964 #endif /* CONFIG_IPV6 */
966 while (*pos
== ' ' || *pos
== '\t') {
975 entry
= os_zalloc(sizeof(*entry
));
980 entry
->shared_secret
= os_strdup(pos
);
981 if (entry
->shared_secret
== NULL
) {
986 entry
->shared_secret_len
= os_strlen(entry
->shared_secret
);
987 entry
->addr
.s_addr
= addr
.s_addr
;
990 for (i
= 0; i
< mask
; i
++)
991 val
|= 1 << (31 - i
);
992 entry
->mask
.s_addr
= htonl(val
);
996 int offset
= mask
/ 8;
998 os_memcpy(entry
->addr6
.s6_addr
, addr6
.s6_addr
, 16);
999 os_memset(entry
->mask6
.s6_addr
, 0xff, offset
);
1001 for (i
= 0; i
< (mask
% 8); i
++)
1002 val
|= 1 << (7 - i
);
1004 entry
->mask6
.s6_addr
[offset
] = val
;
1006 #endif /* CONFIG_IPV6 */
1009 clients
= tail
= entry
;
1017 RADIUS_ERROR("Invalid line %d in '%s'", line
, client_file
);
1018 radius_server_free_clients(NULL
, clients
);
1029 struct radius_server_data
*
1030 radius_server_init(struct radius_server_conf
*conf
)
1032 struct radius_server_data
*data
;
1036 fprintf(stderr
, "RADIUS server compiled without IPv6 "
1040 #endif /* CONFIG_IPV6 */
1042 data
= os_zalloc(sizeof(*data
));
1046 os_get_time(&data
->start_time
);
1047 data
->conf_ctx
= conf
->conf_ctx
;
1048 data
->eap_sim_db_priv
= conf
->eap_sim_db_priv
;
1049 data
->ssl_ctx
= conf
->ssl_ctx
;
1050 data
->ipv6
= conf
->ipv6
;
1051 if (conf
->pac_opaque_encr_key
) {
1052 data
->pac_opaque_encr_key
= os_malloc(16);
1053 os_memcpy(data
->pac_opaque_encr_key
, conf
->pac_opaque_encr_key
,
1056 if (conf
->eap_fast_a_id
) {
1057 data
->eap_fast_a_id
= os_malloc(conf
->eap_fast_a_id_len
);
1058 if (data
->eap_fast_a_id
) {
1059 os_memcpy(data
->eap_fast_a_id
, conf
->eap_fast_a_id
,
1060 conf
->eap_fast_a_id_len
);
1061 data
->eap_fast_a_id_len
= conf
->eap_fast_a_id_len
;
1064 if (conf
->eap_fast_a_id_info
)
1065 data
->eap_fast_a_id_info
= os_strdup(conf
->eap_fast_a_id_info
);
1066 data
->eap_fast_prov
= conf
->eap_fast_prov
;
1067 data
->pac_key_lifetime
= conf
->pac_key_lifetime
;
1068 data
->pac_key_refresh_time
= conf
->pac_key_refresh_time
;
1069 data
->get_eap_user
= conf
->get_eap_user
;
1070 data
->eap_sim_aka_result_ind
= conf
->eap_sim_aka_result_ind
;
1071 data
->tnc
= conf
->tnc
;
1072 data
->wps
= conf
->wps
;
1073 if (conf
->eap_req_id_text
) {
1074 data
->eap_req_id_text
= os_malloc(conf
->eap_req_id_text_len
);
1075 if (data
->eap_req_id_text
) {
1076 os_memcpy(data
->eap_req_id_text
, conf
->eap_req_id_text
,
1077 conf
->eap_req_id_text_len
);
1078 data
->eap_req_id_text_len
= conf
->eap_req_id_text_len
;
1082 data
->clients
= radius_server_read_clients(conf
->client_file
,
1084 if (data
->clients
== NULL
) {
1085 printf("No RADIUS clients configured.\n");
1086 radius_server_deinit(data
);
1092 data
->auth_sock
= radius_server_open_socket6(conf
->auth_port
);
1094 #endif /* CONFIG_IPV6 */
1095 data
->auth_sock
= radius_server_open_socket(conf
->auth_port
);
1096 if (data
->auth_sock
< 0) {
1097 printf("Failed to open UDP socket for RADIUS authentication "
1099 radius_server_deinit(data
);
1102 if (eloop_register_read_sock(data
->auth_sock
,
1103 radius_server_receive_auth
,
1105 radius_server_deinit(data
);
1113 void radius_server_deinit(struct radius_server_data
*data
)
1118 if (data
->auth_sock
>= 0) {
1119 eloop_unregister_read_sock(data
->auth_sock
);
1120 close(data
->auth_sock
);
1123 radius_server_free_clients(data
, data
->clients
);
1125 os_free(data
->pac_opaque_encr_key
);
1126 os_free(data
->eap_fast_a_id
);
1127 os_free(data
->eap_fast_a_id_info
);
1128 os_free(data
->eap_req_id_text
);
1133 int radius_server_get_mib(struct radius_server_data
*data
, char *buf
,
1140 struct radius_client
*cli
;
1142 /* RFC 2619 - RADIUS Authentication Server MIB */
1144 if (data
== NULL
|| buflen
== 0)
1151 uptime
= (now
.sec
- data
->start_time
.sec
) * 100 +
1152 ((now
.usec
- data
->start_time
.usec
) / 10000) % 100;
1153 ret
= os_snprintf(pos
, end
- pos
,
1154 "RADIUS-AUTH-SERVER-MIB\n"
1155 "radiusAuthServIdent=hostapd\n"
1156 "radiusAuthServUpTime=%d\n"
1157 "radiusAuthServResetTime=0\n"
1158 "radiusAuthServConfigReset=4\n",
1160 if (ret
< 0 || ret
>= end
- pos
) {
1166 ret
= os_snprintf(pos
, end
- pos
,
1167 "radiusAuthServTotalAccessRequests=%u\n"
1168 "radiusAuthServTotalInvalidRequests=%u\n"
1169 "radiusAuthServTotalDupAccessRequests=%u\n"
1170 "radiusAuthServTotalAccessAccepts=%u\n"
1171 "radiusAuthServTotalAccessRejects=%u\n"
1172 "radiusAuthServTotalAccessChallenges=%u\n"
1173 "radiusAuthServTotalMalformedAccessRequests=%u\n"
1174 "radiusAuthServTotalBadAuthenticators=%u\n"
1175 "radiusAuthServTotalPacketsDropped=%u\n"
1176 "radiusAuthServTotalUnknownTypes=%u\n",
1177 data
->counters
.access_requests
,
1178 data
->counters
.invalid_requests
,
1179 data
->counters
.dup_access_requests
,
1180 data
->counters
.access_accepts
,
1181 data
->counters
.access_rejects
,
1182 data
->counters
.access_challenges
,
1183 data
->counters
.malformed_access_requests
,
1184 data
->counters
.bad_authenticators
,
1185 data
->counters
.packets_dropped
,
1186 data
->counters
.unknown_types
);
1187 if (ret
< 0 || ret
>= end
- pos
) {
1193 for (cli
= data
->clients
, idx
= 0; cli
; cli
= cli
->next
, idx
++) {
1194 char abuf
[50], mbuf
[50];
1197 if (inet_ntop(AF_INET6
, &cli
->addr6
, abuf
,
1198 sizeof(abuf
)) == NULL
)
1200 if (inet_ntop(AF_INET6
, &cli
->mask6
, abuf
,
1201 sizeof(mbuf
)) == NULL
)
1204 #endif /* CONFIG_IPV6 */
1206 os_strlcpy(abuf
, inet_ntoa(cli
->addr
), sizeof(abuf
));
1207 os_strlcpy(mbuf
, inet_ntoa(cli
->mask
), sizeof(mbuf
));
1210 ret
= os_snprintf(pos
, end
- pos
,
1211 "radiusAuthClientIndex=%u\n"
1212 "radiusAuthClientAddress=%s/%s\n"
1213 "radiusAuthServAccessRequests=%u\n"
1214 "radiusAuthServDupAccessRequests=%u\n"
1215 "radiusAuthServAccessAccepts=%u\n"
1216 "radiusAuthServAccessRejects=%u\n"
1217 "radiusAuthServAccessChallenges=%u\n"
1218 "radiusAuthServMalformedAccessRequests=%u\n"
1219 "radiusAuthServBadAuthenticators=%u\n"
1220 "radiusAuthServPacketsDropped=%u\n"
1221 "radiusAuthServUnknownTypes=%u\n",
1224 cli
->counters
.access_requests
,
1225 cli
->counters
.dup_access_requests
,
1226 cli
->counters
.access_accepts
,
1227 cli
->counters
.access_rejects
,
1228 cli
->counters
.access_challenges
,
1229 cli
->counters
.malformed_access_requests
,
1230 cli
->counters
.bad_authenticators
,
1231 cli
->counters
.packets_dropped
,
1232 cli
->counters
.unknown_types
);
1233 if (ret
< 0 || ret
>= end
- pos
) {
1244 static int radius_server_get_eap_user(void *ctx
, const u8
*identity
,
1245 size_t identity_len
, int phase2
,
1246 struct eap_user
*user
)
1248 struct radius_session
*sess
= ctx
;
1249 struct radius_server_data
*data
= sess
->server
;
1251 return data
->get_eap_user(data
->conf_ctx
, identity
, identity_len
,
1256 static const char * radius_server_get_eap_req_id_text(void *ctx
, size_t *len
)
1258 struct radius_session
*sess
= ctx
;
1259 struct radius_server_data
*data
= sess
->server
;
1260 *len
= data
->eap_req_id_text_len
;
1261 return data
->eap_req_id_text
;
1265 static struct eapol_callbacks radius_server_eapol_cb
=
1267 .get_eap_user
= radius_server_get_eap_user
,
1268 .get_eap_req_id_text
= radius_server_get_eap_req_id_text
,
1272 void radius_server_eap_pending_cb(struct radius_server_data
*data
, void *ctx
)
1274 struct radius_client
*cli
;
1275 struct radius_session
*s
, *sess
= NULL
;
1276 struct radius_msg
*msg
;
1281 for (cli
= data
->clients
; cli
; cli
= cli
->next
) {
1282 for (s
= cli
->sessions
; s
; s
= s
->next
) {
1283 if (s
->eap
== ctx
&& s
->last_msg
) {
1295 RADIUS_DEBUG("No session matched callback ctx");
1299 msg
= sess
->last_msg
;
1300 sess
->last_msg
= NULL
;
1301 eap_sm_pending_cb(sess
->eap
);
1302 if (radius_server_request(data
, msg
,
1303 (struct sockaddr
*) &sess
->last_from
,
1304 sess
->last_fromlen
, cli
,
1305 sess
->last_from_addr
,
1306 sess
->last_from_port
, sess
) == -2)
1307 return; /* msg was stored with the session */
1309 radius_msg_free(msg
);