3 * Copyright (c) 2002-2009, 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.
19 #include "radius_client.h"
22 /* Defaults for RADIUS retransmit values (exponential backoff) */
25 * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
27 #define RADIUS_CLIENT_FIRST_WAIT 3
30 * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
32 #define RADIUS_CLIENT_MAX_WAIT 120
35 * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
37 * Maximum number of retransmit attempts before the entry is removed from
40 #define RADIUS_CLIENT_MAX_RETRIES 10
43 * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
45 * Maximum number of entries in retransmit list (oldest entries will be
46 * removed, if this limit is exceeded).
48 #define RADIUS_CLIENT_MAX_ENTRIES 30
51 * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
53 * The number of failed retry attempts after which the RADIUS server will be
54 * changed (if one of more backup servers are configured).
56 #define RADIUS_CLIENT_NUM_FAILOVER 4
60 * struct radius_rx_handler - RADIUS client RX handler
62 * This data structure is used internally inside the RADIUS client module to
63 * store registered RX handlers. These handlers are registered by calls to
64 * radius_client_register() and unregistered when the RADIUS client is
65 * deinitialized with a call to radius_client_deinit().
67 struct radius_rx_handler
{
69 * handler - Received RADIUS message handler
71 RadiusRxResult (*handler
)(struct radius_msg
*msg
,
72 struct radius_msg
*req
,
73 const u8
*shared_secret
,
74 size_t shared_secret_len
,
78 * data - Context data for the handler
85 * struct radius_msg_list - RADIUS client message retransmit list
87 * This data structure is used internally inside the RADIUS client module to
88 * store pending RADIUS requests that may still need to be retransmitted.
90 struct radius_msg_list
{
92 * addr - STA/client address
94 * This is used to find RADIUS messages for the same STA.
99 * msg - RADIUS message
101 struct radius_msg
*msg
;
104 * msg_type - Message type
109 * first_try - Time of the first transmission attempt
114 * next_try - Time for the next transmission attempt
119 * attempts - Number of transmission attempts
124 * next_wait - Next retransmission wait time in seconds
129 * last_attempt - Time of the last transmission attempt
131 struct os_time last_attempt
;
134 * shared_secret - Shared secret with the target RADIUS server
136 const u8
*shared_secret
;
139 * shared_secret_len - shared_secret length in octets
141 size_t shared_secret_len
;
143 /* TODO: server config with failover to backup server(s) */
146 * next - Next message in the list
148 struct radius_msg_list
*next
;
153 * struct radius_client_data - Internal RADIUS client data
155 * This data structure is used internally inside the RADIUS client module.
156 * External users allocate this by calling radius_client_init() and free it by
157 * calling radius_client_deinit(). The pointer to this opaque data is used in
158 * calls to other functions as an identifier for the RADIUS client instance.
160 struct radius_client_data
{
162 * ctx - Context pointer for hostapd_logger() callbacks
167 * conf - RADIUS client configuration (list of RADIUS servers to use)
169 struct hostapd_radius_servers
*conf
;
172 * auth_serv_sock - IPv4 socket for RADIUS authentication messages
177 * acct_serv_sock - IPv4 socket for RADIUS accounting messages
182 * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
187 * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
192 * auth_sock - Currently used socket for RADIUS authentication server
197 * acct_sock - Currently used socket for RADIUS accounting server
202 * auth_handlers - Authentication message handlers
204 struct radius_rx_handler
*auth_handlers
;
207 * num_auth_handlers - Number of handlers in auth_handlers
209 size_t num_auth_handlers
;
212 * acct_handlers - Accounting message handlers
214 struct radius_rx_handler
*acct_handlers
;
217 * num_acct_handlers - Number of handlers in acct_handlers
219 size_t num_acct_handlers
;
222 * msgs - Pending outgoing RADIUS messages
224 struct radius_msg_list
*msgs
;
227 * num_msgs - Number of pending messages in the msgs list
232 * next_radius_identifier - Next RADIUS message identifier to use
234 u8 next_radius_identifier
;
239 radius_change_server(struct radius_client_data
*radius
,
240 struct hostapd_radius_server
*nserv
,
241 struct hostapd_radius_server
*oserv
,
242 int sock
, int sock6
, int auth
);
243 static int radius_client_init_acct(struct radius_client_data
*radius
);
244 static int radius_client_init_auth(struct radius_client_data
*radius
);
247 static void radius_client_msg_free(struct radius_msg_list
*req
)
249 radius_msg_free(req
->msg
);
255 * radius_client_register - Register a RADIUS client RX handler
256 * @radius: RADIUS client context from radius_client_init()
257 * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
258 * @handler: Handler for received RADIUS messages
259 * @data: Context pointer for handler callbacks
260 * Returns: 0 on success, -1 on failure
262 * This function is used to register a handler for processing received RADIUS
263 * authentication and accounting messages. The handler() callback function will
264 * be called whenever a RADIUS message is received from the active server.
266 * There can be multiple registered RADIUS message handlers. The handlers will
267 * be called in order until one of them indicates that it has processed or
268 * queued the message.
270 int radius_client_register(struct radius_client_data
*radius
,
272 RadiusRxResult (*handler
)(struct radius_msg
*msg
,
273 struct radius_msg
*req
,
274 const u8
*shared_secret
,
275 size_t shared_secret_len
,
279 struct radius_rx_handler
**handlers
, *newh
;
282 if (msg_type
== RADIUS_ACCT
) {
283 handlers
= &radius
->acct_handlers
;
284 num
= &radius
->num_acct_handlers
;
286 handlers
= &radius
->auth_handlers
;
287 num
= &radius
->num_auth_handlers
;
290 newh
= os_realloc(*handlers
,
291 (*num
+ 1) * sizeof(struct radius_rx_handler
));
295 newh
[*num
].handler
= handler
;
296 newh
[*num
].data
= data
;
304 static void radius_client_handle_send_error(struct radius_client_data
*radius
,
305 int s
, RadiusType msg_type
)
307 #ifndef CONFIG_NATIVE_WINDOWS
309 perror("send[RADIUS]");
310 if (_errno
== ENOTCONN
|| _errno
== EDESTADDRREQ
|| _errno
== EINVAL
||
312 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
314 "Send failed - maybe interface status changed -"
315 " try to connect again");
316 eloop_unregister_read_sock(s
);
318 if (msg_type
== RADIUS_ACCT
|| msg_type
== RADIUS_ACCT_INTERIM
)
319 radius_client_init_acct(radius
);
321 radius_client_init_auth(radius
);
323 #endif /* CONFIG_NATIVE_WINDOWS */
327 static int radius_client_retransmit(struct radius_client_data
*radius
,
328 struct radius_msg_list
*entry
,
331 struct hostapd_radius_servers
*conf
= radius
->conf
;
335 if (entry
->msg_type
== RADIUS_ACCT
||
336 entry
->msg_type
== RADIUS_ACCT_INTERIM
) {
337 s
= radius
->acct_sock
;
338 if (entry
->attempts
== 0)
339 conf
->acct_server
->requests
++;
341 conf
->acct_server
->timeouts
++;
342 conf
->acct_server
->retransmissions
++;
345 s
= radius
->auth_sock
;
346 if (entry
->attempts
== 0)
347 conf
->auth_server
->requests
++;
349 conf
->auth_server
->timeouts
++;
350 conf
->auth_server
->retransmissions
++;
354 /* retransmit; remove entry if too many attempts */
356 hostapd_logger(radius
->ctx
, entry
->addr
, HOSTAPD_MODULE_RADIUS
,
357 HOSTAPD_LEVEL_DEBUG
, "Resending RADIUS message (id=%d)",
358 radius_msg_get_hdr(entry
->msg
)->identifier
);
360 os_get_time(&entry
->last_attempt
);
361 buf
= radius_msg_get_buf(entry
->msg
);
362 if (send(s
, wpabuf_head(buf
), wpabuf_len(buf
), 0) < 0)
363 radius_client_handle_send_error(radius
, s
, entry
->msg_type
);
365 entry
->next_try
= now
+ entry
->next_wait
;
366 entry
->next_wait
*= 2;
367 if (entry
->next_wait
> RADIUS_CLIENT_MAX_WAIT
)
368 entry
->next_wait
= RADIUS_CLIENT_MAX_WAIT
;
369 if (entry
->attempts
>= RADIUS_CLIENT_MAX_RETRIES
) {
370 printf("Removing un-ACKed RADIUS message due to too many "
371 "failed retransmit attempts\n");
379 static void radius_client_timer(void *eloop_ctx
, void *timeout_ctx
)
381 struct radius_client_data
*radius
= eloop_ctx
;
382 struct hostapd_radius_servers
*conf
= radius
->conf
;
385 struct radius_msg_list
*entry
, *prev
, *tmp
;
386 int auth_failover
= 0, acct_failover
= 0;
389 entry
= radius
->msgs
;
398 if (now
.sec
>= entry
->next_try
&&
399 radius_client_retransmit(radius
, entry
, now
.sec
)) {
401 prev
->next
= entry
->next
;
403 radius
->msgs
= entry
->next
;
407 radius_client_msg_free(tmp
);
412 if (entry
->attempts
> RADIUS_CLIENT_NUM_FAILOVER
) {
413 if (entry
->msg_type
== RADIUS_ACCT
||
414 entry
->msg_type
== RADIUS_ACCT_INTERIM
)
420 if (first
== 0 || entry
->next_try
< first
)
421 first
= entry
->next_try
;
430 eloop_register_timeout(first
- now
.sec
, 0,
431 radius_client_timer
, radius
, NULL
);
432 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
433 HOSTAPD_LEVEL_DEBUG
, "Next RADIUS client "
434 "retransmit in %ld seconds",
435 (long int) (first
- now
.sec
));
438 if (auth_failover
&& conf
->num_auth_servers
> 1) {
439 struct hostapd_radius_server
*next
, *old
;
440 old
= conf
->auth_server
;
441 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
442 HOSTAPD_LEVEL_NOTICE
,
443 "No response from Authentication server "
445 hostapd_ip_txt(&old
->addr
, abuf
, sizeof(abuf
)),
448 for (entry
= radius
->msgs
; entry
; entry
= entry
->next
) {
449 if (entry
->msg_type
== RADIUS_AUTH
)
454 if (next
> &(conf
->auth_servers
[conf
->num_auth_servers
- 1]))
455 next
= conf
->auth_servers
;
456 conf
->auth_server
= next
;
457 radius_change_server(radius
, next
, old
,
458 radius
->auth_serv_sock
,
459 radius
->auth_serv_sock6
, 1);
462 if (acct_failover
&& conf
->num_acct_servers
> 1) {
463 struct hostapd_radius_server
*next
, *old
;
464 old
= conf
->acct_server
;
465 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
466 HOSTAPD_LEVEL_NOTICE
,
467 "No response from Accounting server "
469 hostapd_ip_txt(&old
->addr
, abuf
, sizeof(abuf
)),
472 for (entry
= radius
->msgs
; entry
; entry
= entry
->next
) {
473 if (entry
->msg_type
== RADIUS_ACCT
||
474 entry
->msg_type
== RADIUS_ACCT_INTERIM
)
479 if (next
> &conf
->acct_servers
[conf
->num_acct_servers
- 1])
480 next
= conf
->acct_servers
;
481 conf
->acct_server
= next
;
482 radius_change_server(radius
, next
, old
,
483 radius
->acct_serv_sock
,
484 radius
->acct_serv_sock6
, 0);
489 static void radius_client_update_timeout(struct radius_client_data
*radius
)
493 struct radius_msg_list
*entry
;
495 eloop_cancel_timeout(radius_client_timer
, radius
, NULL
);
497 if (radius
->msgs
== NULL
) {
502 for (entry
= radius
->msgs
; entry
; entry
= entry
->next
) {
503 if (first
== 0 || entry
->next_try
< first
)
504 first
= entry
->next_try
;
510 eloop_register_timeout(first
- now
.sec
, 0, radius_client_timer
, radius
,
512 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
513 HOSTAPD_LEVEL_DEBUG
, "Next RADIUS client retransmit in"
514 " %ld seconds\n", (long int) (first
- now
.sec
));
518 static void radius_client_list_add(struct radius_client_data
*radius
,
519 struct radius_msg
*msg
,
521 const u8
*shared_secret
,
522 size_t shared_secret_len
, const u8
*addr
)
524 struct radius_msg_list
*entry
, *prev
;
526 if (eloop_terminated()) {
527 /* No point in adding entries to retransmit queue since event
528 * loop has already been terminated. */
529 radius_msg_free(msg
);
533 entry
= os_zalloc(sizeof(*entry
));
535 printf("Failed to add RADIUS packet into retransmit list\n");
536 radius_msg_free(msg
);
541 os_memcpy(entry
->addr
, addr
, ETH_ALEN
);
543 entry
->msg_type
= msg_type
;
544 entry
->shared_secret
= shared_secret
;
545 entry
->shared_secret_len
= shared_secret_len
;
546 os_get_time(&entry
->last_attempt
);
547 entry
->first_try
= entry
->last_attempt
.sec
;
548 entry
->next_try
= entry
->first_try
+ RADIUS_CLIENT_FIRST_WAIT
;
550 entry
->next_wait
= RADIUS_CLIENT_FIRST_WAIT
* 2;
551 entry
->next
= radius
->msgs
;
552 radius
->msgs
= entry
;
553 radius_client_update_timeout(radius
);
555 if (radius
->num_msgs
>= RADIUS_CLIENT_MAX_ENTRIES
) {
556 printf("Removing the oldest un-ACKed RADIUS packet due to "
557 "retransmit list limits.\n");
559 while (entry
->next
) {
565 radius_client_msg_free(entry
);
572 static void radius_client_list_del(struct radius_client_data
*radius
,
573 RadiusType msg_type
, const u8
*addr
)
575 struct radius_msg_list
*entry
, *prev
, *tmp
;
580 entry
= radius
->msgs
;
583 if (entry
->msg_type
== msg_type
&&
584 os_memcmp(entry
->addr
, addr
, ETH_ALEN
) == 0) {
586 prev
->next
= entry
->next
;
588 radius
->msgs
= entry
->next
;
591 hostapd_logger(radius
->ctx
, addr
,
592 HOSTAPD_MODULE_RADIUS
,
594 "Removing matching RADIUS message");
595 radius_client_msg_free(tmp
);
606 * radius_client_send - Send a RADIUS request
607 * @radius: RADIUS client context from radius_client_init()
608 * @msg: RADIUS message to be sent
609 * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
610 * @addr: MAC address of the device related to this message or %NULL
611 * Returns: 0 on success, -1 on failure
613 * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
614 * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
615 * between accounting and interim accounting messages is that the interim
616 * message will override any pending interim accounting updates while a new
617 * accounting message does not remove any pending messages.
619 * The message is added on the retransmission queue and will be retransmitted
620 * automatically until a response is received or maximum number of retries
621 * (RADIUS_CLIENT_MAX_RETRIES) is reached.
623 * The related device MAC address can be used to identify pending messages that
624 * can be removed with radius_client_flush_auth() or with interim accounting
627 int radius_client_send(struct radius_client_data
*radius
,
628 struct radius_msg
*msg
, RadiusType msg_type
,
631 struct hostapd_radius_servers
*conf
= radius
->conf
;
632 const u8
*shared_secret
;
633 size_t shared_secret_len
;
638 if (msg_type
== RADIUS_ACCT_INTERIM
) {
639 /* Remove any pending interim acct update for the same STA. */
640 radius_client_list_del(radius
, msg_type
, addr
);
643 if (msg_type
== RADIUS_ACCT
|| msg_type
== RADIUS_ACCT_INTERIM
) {
644 if (conf
->acct_server
== NULL
) {
645 hostapd_logger(radius
->ctx
, NULL
,
646 HOSTAPD_MODULE_RADIUS
,
648 "No accounting server configured");
651 shared_secret
= conf
->acct_server
->shared_secret
;
652 shared_secret_len
= conf
->acct_server
->shared_secret_len
;
653 radius_msg_finish_acct(msg
, shared_secret
, shared_secret_len
);
655 s
= radius
->acct_sock
;
656 conf
->acct_server
->requests
++;
658 if (conf
->auth_server
== NULL
) {
659 hostapd_logger(radius
->ctx
, NULL
,
660 HOSTAPD_MODULE_RADIUS
,
662 "No authentication server configured");
665 shared_secret
= conf
->auth_server
->shared_secret
;
666 shared_secret_len
= conf
->auth_server
->shared_secret_len
;
667 radius_msg_finish(msg
, shared_secret
, shared_secret_len
);
668 name
= "authentication";
669 s
= radius
->auth_sock
;
670 conf
->auth_server
->requests
++;
673 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
674 HOSTAPD_LEVEL_DEBUG
, "Sending RADIUS message to %s "
677 radius_msg_dump(msg
);
679 buf
= radius_msg_get_buf(msg
);
680 res
= send(s
, wpabuf_head(buf
), wpabuf_len(buf
), 0);
682 radius_client_handle_send_error(radius
, s
, msg_type
);
684 radius_client_list_add(radius
, msg
, msg_type
, shared_secret
,
685 shared_secret_len
, addr
);
691 static void radius_client_receive(int sock
, void *eloop_ctx
, void *sock_ctx
)
693 struct radius_client_data
*radius
= eloop_ctx
;
694 struct hostapd_radius_servers
*conf
= radius
->conf
;
695 RadiusType msg_type
= (RadiusType
) sock_ctx
;
697 unsigned char buf
[3000];
698 struct radius_msg
*msg
;
699 struct radius_hdr
*hdr
;
700 struct radius_rx_handler
*handlers
;
701 size_t num_handlers
, i
;
702 struct radius_msg_list
*req
, *prev_req
;
704 struct hostapd_radius_server
*rconf
;
705 int invalid_authenticator
= 0;
707 if (msg_type
== RADIUS_ACCT
) {
708 handlers
= radius
->acct_handlers
;
709 num_handlers
= radius
->num_acct_handlers
;
710 rconf
= conf
->acct_server
;
712 handlers
= radius
->auth_handlers
;
713 num_handlers
= radius
->num_auth_handlers
;
714 rconf
= conf
->auth_server
;
717 len
= recv(sock
, buf
, sizeof(buf
), MSG_DONTWAIT
);
719 perror("recv[RADIUS]");
722 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
723 HOSTAPD_LEVEL_DEBUG
, "Received %d bytes from RADIUS "
725 if (len
== sizeof(buf
)) {
726 printf("Possibly too long UDP frame for our buffer - "
731 msg
= radius_msg_parse(buf
, len
);
733 printf("Parsing incoming RADIUS frame failed\n");
734 rconf
->malformed_responses
++;
737 hdr
= radius_msg_get_hdr(msg
);
739 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
740 HOSTAPD_LEVEL_DEBUG
, "Received RADIUS message");
742 radius_msg_dump(msg
);
745 case RADIUS_CODE_ACCESS_ACCEPT
:
746 rconf
->access_accepts
++;
748 case RADIUS_CODE_ACCESS_REJECT
:
749 rconf
->access_rejects
++;
751 case RADIUS_CODE_ACCESS_CHALLENGE
:
752 rconf
->access_challenges
++;
754 case RADIUS_CODE_ACCOUNTING_RESPONSE
:
762 /* TODO: also match by src addr:port of the packet when using
763 * alternative RADIUS servers (?) */
764 if ((req
->msg_type
== msg_type
||
765 (req
->msg_type
== RADIUS_ACCT_INTERIM
&&
766 msg_type
== RADIUS_ACCT
)) &&
767 radius_msg_get_hdr(req
->msg
)->identifier
==
776 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
778 "No matching RADIUS request found (type=%d "
779 "id=%d) - dropping packet",
780 msg_type
, hdr
->identifier
);
785 roundtrip
= (now
.sec
- req
->last_attempt
.sec
) * 100 +
786 (now
.usec
- req
->last_attempt
.usec
) / 10000;
787 hostapd_logger(radius
->ctx
, req
->addr
, HOSTAPD_MODULE_RADIUS
,
789 "Received RADIUS packet matched with a pending "
790 "request, round trip time %d.%02d sec",
791 roundtrip
/ 100, roundtrip
% 100);
792 rconf
->round_trip_time
= roundtrip
;
794 /* Remove ACKed RADIUS packet from retransmit list */
796 prev_req
->next
= req
->next
;
798 radius
->msgs
= req
->next
;
801 for (i
= 0; i
< num_handlers
; i
++) {
803 res
= handlers
[i
].handler(msg
, req
->msg
, req
->shared_secret
,
804 req
->shared_secret_len
,
807 case RADIUS_RX_PROCESSED
:
808 radius_msg_free(msg
);
810 case RADIUS_RX_QUEUED
:
811 radius_client_msg_free(req
);
813 case RADIUS_RX_INVALID_AUTHENTICATOR
:
814 invalid_authenticator
++;
816 case RADIUS_RX_UNKNOWN
:
817 /* continue with next handler */
822 if (invalid_authenticator
)
823 rconf
->bad_authenticators
++;
825 rconf
->unknown_types
++;
826 hostapd_logger(radius
->ctx
, req
->addr
, HOSTAPD_MODULE_RADIUS
,
827 HOSTAPD_LEVEL_DEBUG
, "No RADIUS RX handler found "
828 "(type=%d code=%d id=%d)%s - dropping packet",
829 msg_type
, hdr
->code
, hdr
->identifier
,
830 invalid_authenticator
? " [INVALID AUTHENTICATOR]" :
832 radius_client_msg_free(req
);
835 radius_msg_free(msg
);
840 * radius_client_get_id - Get an identifier for a new RADIUS message
841 * @radius: RADIUS client context from radius_client_init()
842 * Returns: Allocated identifier
844 * This function is used to fetch a unique (among pending requests) identifier
845 * for a new RADIUS message.
847 u8
radius_client_get_id(struct radius_client_data
*radius
)
849 struct radius_msg_list
*entry
, *prev
, *_remove
;
850 u8 id
= radius
->next_radius_identifier
++;
852 /* remove entries with matching id from retransmit list to avoid
853 * using new reply from the RADIUS server with an old request */
854 entry
= radius
->msgs
;
857 if (radius_msg_get_hdr(entry
->msg
)->identifier
== id
) {
858 hostapd_logger(radius
->ctx
, entry
->addr
,
859 HOSTAPD_MODULE_RADIUS
,
861 "Removing pending RADIUS message, "
862 "since its id (%d) is reused", id
);
864 prev
->next
= entry
->next
;
866 radius
->msgs
= entry
->next
;
875 radius_client_msg_free(_remove
);
883 * radius_client_flush - Flush all pending RADIUS client messages
884 * @radius: RADIUS client context from radius_client_init()
885 * @only_auth: Whether only authentication messages are removed
887 void radius_client_flush(struct radius_client_data
*radius
, int only_auth
)
889 struct radius_msg_list
*entry
, *prev
, *tmp
;
895 entry
= radius
->msgs
;
898 if (!only_auth
|| entry
->msg_type
== RADIUS_AUTH
) {
900 prev
->next
= entry
->next
;
902 radius
->msgs
= entry
->next
;
906 radius_client_msg_free(tmp
);
914 if (radius
->msgs
== NULL
)
915 eloop_cancel_timeout(radius_client_timer
, radius
, NULL
);
919 static void radius_client_update_acct_msgs(struct radius_client_data
*radius
,
920 const u8
*shared_secret
,
921 size_t shared_secret_len
)
923 struct radius_msg_list
*entry
;
928 for (entry
= radius
->msgs
; entry
; entry
= entry
->next
) {
929 if (entry
->msg_type
== RADIUS_ACCT
) {
930 entry
->shared_secret
= shared_secret
;
931 entry
->shared_secret_len
= shared_secret_len
;
932 radius_msg_finish_acct(entry
->msg
, shared_secret
,
940 radius_change_server(struct radius_client_data
*radius
,
941 struct hostapd_radius_server
*nserv
,
942 struct hostapd_radius_server
*oserv
,
943 int sock
, int sock6
, int auth
)
945 struct sockaddr_in serv
, claddr
;
947 struct sockaddr_in6 serv6
, claddr6
;
948 #endif /* CONFIG_IPV6 */
949 struct sockaddr
*addr
, *cl_addr
;
950 socklen_t addrlen
, claddrlen
;
953 struct radius_msg_list
*entry
;
954 struct hostapd_radius_servers
*conf
= radius
->conf
;
956 hostapd_logger(radius
->ctx
, NULL
, HOSTAPD_MODULE_RADIUS
,
959 auth
? "Authentication" : "Accounting",
960 hostapd_ip_txt(&nserv
->addr
, abuf
, sizeof(abuf
)),
963 if (!oserv
|| nserv
->shared_secret_len
!= oserv
->shared_secret_len
||
964 os_memcmp(nserv
->shared_secret
, oserv
->shared_secret
,
965 nserv
->shared_secret_len
) != 0) {
966 /* Pending RADIUS packets used different shared secret, so
967 * they need to be modified. Update accounting message
968 * authenticators here. Authentication messages are removed
969 * since they would require more changes and the new RADIUS
970 * server may not be prepared to receive them anyway due to
971 * missing state information. Client will likely retry
972 * authentication, so this should not be an issue. */
974 radius_client_flush(radius
, 1);
976 radius_client_update_acct_msgs(
977 radius
, nserv
->shared_secret
,
978 nserv
->shared_secret_len
);
982 /* Reset retry counters for the new server */
983 for (entry
= radius
->msgs
; entry
; entry
= entry
->next
) {
984 if ((auth
&& entry
->msg_type
!= RADIUS_AUTH
) ||
985 (!auth
&& entry
->msg_type
!= RADIUS_ACCT
))
987 entry
->next_try
= entry
->first_try
+ RADIUS_CLIENT_FIRST_WAIT
;
989 entry
->next_wait
= RADIUS_CLIENT_FIRST_WAIT
* 2;
993 eloop_cancel_timeout(radius_client_timer
, radius
, NULL
);
994 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT
, 0,
995 radius_client_timer
, radius
, NULL
);
998 switch (nserv
->addr
.af
) {
1000 os_memset(&serv
, 0, sizeof(serv
));
1001 serv
.sin_family
= AF_INET
;
1002 serv
.sin_addr
.s_addr
= nserv
->addr
.u
.v4
.s_addr
;
1003 serv
.sin_port
= htons(nserv
->port
);
1004 addr
= (struct sockaddr
*) &serv
;
1005 addrlen
= sizeof(serv
);
1010 os_memset(&serv6
, 0, sizeof(serv6
));
1011 serv6
.sin6_family
= AF_INET6
;
1012 os_memcpy(&serv6
.sin6_addr
, &nserv
->addr
.u
.v6
,
1013 sizeof(struct in6_addr
));
1014 serv6
.sin6_port
= htons(nserv
->port
);
1015 addr
= (struct sockaddr
*) &serv6
;
1016 addrlen
= sizeof(serv6
);
1019 #endif /* CONFIG_IPV6 */
1024 if (conf
->force_client_addr
) {
1025 switch (conf
->client_addr
.af
) {
1027 os_memset(&claddr
, 0, sizeof(claddr
));
1028 claddr
.sin_family
= AF_INET
;
1029 claddr
.sin_addr
.s_addr
= conf
->client_addr
.u
.v4
.s_addr
;
1030 claddr
.sin_port
= htons(0);
1031 cl_addr
= (struct sockaddr
*) &claddr
;
1032 claddrlen
= sizeof(claddr
);
1036 os_memset(&claddr6
, 0, sizeof(claddr6
));
1037 claddr6
.sin6_family
= AF_INET6
;
1038 os_memcpy(&claddr6
.sin6_addr
, &conf
->client_addr
.u
.v6
,
1039 sizeof(struct in6_addr
));
1040 claddr6
.sin6_port
= htons(0);
1041 cl_addr
= (struct sockaddr
*) &claddr6
;
1042 claddrlen
= sizeof(claddr6
);
1044 #endif /* CONFIG_IPV6 */
1049 if (bind(sel_sock
, cl_addr
, claddrlen
) < 0) {
1050 perror("bind[radius]");
1055 if (connect(sel_sock
, addr
, addrlen
) < 0) {
1056 perror("connect[radius]");
1060 #ifndef CONFIG_NATIVE_WINDOWS
1061 switch (nserv
->addr
.af
) {
1063 claddrlen
= sizeof(claddr
);
1064 getsockname(sel_sock
, (struct sockaddr
*) &claddr
, &claddrlen
);
1065 wpa_printf(MSG_DEBUG
, "RADIUS local address: %s:%u",
1066 inet_ntoa(claddr
.sin_addr
), ntohs(claddr
.sin_port
));
1070 claddrlen
= sizeof(claddr6
);
1071 getsockname(sel_sock
, (struct sockaddr
*) &claddr6
,
1073 wpa_printf(MSG_DEBUG
, "RADIUS local address: %s:%u",
1074 inet_ntop(AF_INET6
, &claddr6
.sin6_addr
,
1075 abuf
, sizeof(abuf
)),
1076 ntohs(claddr6
.sin6_port
));
1079 #endif /* CONFIG_IPV6 */
1081 #endif /* CONFIG_NATIVE_WINDOWS */
1084 radius
->auth_sock
= sel_sock
;
1086 radius
->acct_sock
= sel_sock
;
1092 static void radius_retry_primary_timer(void *eloop_ctx
, void *timeout_ctx
)
1094 struct radius_client_data
*radius
= eloop_ctx
;
1095 struct hostapd_radius_servers
*conf
= radius
->conf
;
1096 struct hostapd_radius_server
*oserv
;
1098 if (radius
->auth_sock
>= 0 && conf
->auth_servers
&&
1099 conf
->auth_server
!= conf
->auth_servers
) {
1100 oserv
= conf
->auth_server
;
1101 conf
->auth_server
= conf
->auth_servers
;
1102 radius_change_server(radius
, conf
->auth_server
, oserv
,
1103 radius
->auth_serv_sock
,
1104 radius
->auth_serv_sock6
, 1);
1107 if (radius
->acct_sock
>= 0 && conf
->acct_servers
&&
1108 conf
->acct_server
!= conf
->acct_servers
) {
1109 oserv
= conf
->acct_server
;
1110 conf
->acct_server
= conf
->acct_servers
;
1111 radius_change_server(radius
, conf
->acct_server
, oserv
,
1112 radius
->acct_serv_sock
,
1113 radius
->acct_serv_sock6
, 0);
1116 if (conf
->retry_primary_interval
)
1117 eloop_register_timeout(conf
->retry_primary_interval
, 0,
1118 radius_retry_primary_timer
, radius
,
1123 static int radius_client_disable_pmtu_discovery(int s
)
1126 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1127 /* Turn off Path MTU discovery on IPv4/UDP sockets. */
1128 int action
= IP_PMTUDISC_DONT
;
1129 r
= setsockopt(s
, IPPROTO_IP
, IP_MTU_DISCOVER
, &action
,
1132 wpa_printf(MSG_ERROR
, "Failed to set IP_MTU_DISCOVER: "
1133 "%s", strerror(errno
));
1139 static int radius_client_init_auth(struct radius_client_data
*radius
)
1141 struct hostapd_radius_servers
*conf
= radius
->conf
;
1144 radius
->auth_serv_sock
= socket(PF_INET
, SOCK_DGRAM
, 0);
1145 if (radius
->auth_serv_sock
< 0)
1146 perror("socket[PF_INET,SOCK_DGRAM]");
1148 radius_client_disable_pmtu_discovery(radius
->auth_serv_sock
);
1153 radius
->auth_serv_sock6
= socket(PF_INET6
, SOCK_DGRAM
, 0);
1154 if (radius
->auth_serv_sock6
< 0)
1155 perror("socket[PF_INET6,SOCK_DGRAM]");
1158 #endif /* CONFIG_IPV6 */
1163 radius_change_server(radius
, conf
->auth_server
, NULL
,
1164 radius
->auth_serv_sock
, radius
->auth_serv_sock6
,
1167 if (radius
->auth_serv_sock
>= 0 &&
1168 eloop_register_read_sock(radius
->auth_serv_sock
,
1169 radius_client_receive
, radius
,
1170 (void *) RADIUS_AUTH
)) {
1171 printf("Could not register read socket for authentication "
1177 if (radius
->auth_serv_sock6
>= 0 &&
1178 eloop_register_read_sock(radius
->auth_serv_sock6
,
1179 radius_client_receive
, radius
,
1180 (void *) RADIUS_AUTH
)) {
1181 printf("Could not register read socket for authentication "
1185 #endif /* CONFIG_IPV6 */
1191 static int radius_client_init_acct(struct radius_client_data
*radius
)
1193 struct hostapd_radius_servers
*conf
= radius
->conf
;
1196 radius
->acct_serv_sock
= socket(PF_INET
, SOCK_DGRAM
, 0);
1197 if (radius
->acct_serv_sock
< 0)
1198 perror("socket[PF_INET,SOCK_DGRAM]");
1200 radius_client_disable_pmtu_discovery(radius
->acct_serv_sock
);
1205 radius
->acct_serv_sock6
= socket(PF_INET6
, SOCK_DGRAM
, 0);
1206 if (radius
->acct_serv_sock6
< 0)
1207 perror("socket[PF_INET6,SOCK_DGRAM]");
1210 #endif /* CONFIG_IPV6 */
1215 radius_change_server(radius
, conf
->acct_server
, NULL
,
1216 radius
->acct_serv_sock
, radius
->acct_serv_sock6
,
1219 if (radius
->acct_serv_sock
>= 0 &&
1220 eloop_register_read_sock(radius
->acct_serv_sock
,
1221 radius_client_receive
, radius
,
1222 (void *) RADIUS_ACCT
)) {
1223 printf("Could not register read socket for accounting "
1229 if (radius
->acct_serv_sock6
>= 0 &&
1230 eloop_register_read_sock(radius
->acct_serv_sock6
,
1231 radius_client_receive
, radius
,
1232 (void *) RADIUS_ACCT
)) {
1233 printf("Could not register read socket for accounting "
1237 #endif /* CONFIG_IPV6 */
1244 * radius_client_init - Initialize RADIUS client
1245 * @ctx: Callback context to be used in hostapd_logger() calls
1246 * @conf: RADIUS client configuration (RADIUS servers)
1247 * Returns: Pointer to private RADIUS client context or %NULL on failure
1249 * The caller is responsible for keeping the configuration data available for
1250 * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
1251 * called for the returned context pointer.
1253 struct radius_client_data
*
1254 radius_client_init(void *ctx
, struct hostapd_radius_servers
*conf
)
1256 struct radius_client_data
*radius
;
1258 radius
= os_zalloc(sizeof(struct radius_client_data
));
1263 radius
->conf
= conf
;
1264 radius
->auth_serv_sock
= radius
->acct_serv_sock
=
1265 radius
->auth_serv_sock6
= radius
->acct_serv_sock6
=
1266 radius
->auth_sock
= radius
->acct_sock
= -1;
1268 if (conf
->auth_server
&& radius_client_init_auth(radius
)) {
1269 radius_client_deinit(radius
);
1273 if (conf
->acct_server
&& radius_client_init_acct(radius
)) {
1274 radius_client_deinit(radius
);
1278 if (conf
->retry_primary_interval
)
1279 eloop_register_timeout(conf
->retry_primary_interval
, 0,
1280 radius_retry_primary_timer
, radius
,
1288 * radius_client_deinit - Deinitialize RADIUS client
1289 * @radius: RADIUS client context from radius_client_init()
1291 void radius_client_deinit(struct radius_client_data
*radius
)
1296 if (radius
->auth_serv_sock
>= 0)
1297 eloop_unregister_read_sock(radius
->auth_serv_sock
);
1298 if (radius
->acct_serv_sock
>= 0)
1299 eloop_unregister_read_sock(radius
->acct_serv_sock
);
1301 if (radius
->auth_serv_sock6
>= 0)
1302 eloop_unregister_read_sock(radius
->auth_serv_sock6
);
1303 if (radius
->acct_serv_sock6
>= 0)
1304 eloop_unregister_read_sock(radius
->acct_serv_sock6
);
1305 #endif /* CONFIG_IPV6 */
1307 eloop_cancel_timeout(radius_retry_primary_timer
, radius
, NULL
);
1309 radius_client_flush(radius
, 0);
1310 os_free(radius
->auth_handlers
);
1311 os_free(radius
->acct_handlers
);
1317 * radius_client_flush_auth - Flush pending RADIUS messages for an address
1318 * @radius: RADIUS client context from radius_client_init()
1319 * @addr: MAC address of the related device
1321 * This function can be used to remove pending RADIUS authentication messages
1322 * that are related to a specific device. The addr parameter is matched with
1323 * the one used in radius_client_send() call that was used to transmit the
1324 * authentication request.
1326 void radius_client_flush_auth(struct radius_client_data
*radius
,
1329 struct radius_msg_list
*entry
, *prev
, *tmp
;
1332 entry
= radius
->msgs
;
1334 if (entry
->msg_type
== RADIUS_AUTH
&&
1335 os_memcmp(entry
->addr
, addr
, ETH_ALEN
) == 0) {
1336 hostapd_logger(radius
->ctx
, addr
,
1337 HOSTAPD_MODULE_RADIUS
,
1338 HOSTAPD_LEVEL_DEBUG
,
1339 "Removing pending RADIUS authentication"
1340 " message for removed client");
1343 prev
->next
= entry
->next
;
1345 radius
->msgs
= entry
->next
;
1348 entry
= entry
->next
;
1349 radius_client_msg_free(tmp
);
1355 entry
= entry
->next
;
1360 static int radius_client_dump_auth_server(char *buf
, size_t buflen
,
1361 struct hostapd_radius_server
*serv
,
1362 struct radius_client_data
*cli
)
1365 struct radius_msg_list
*msg
;
1369 for (msg
= cli
->msgs
; msg
; msg
= msg
->next
) {
1370 if (msg
->msg_type
== RADIUS_AUTH
)
1375 return os_snprintf(buf
, buflen
,
1376 "radiusAuthServerIndex=%d\n"
1377 "radiusAuthServerAddress=%s\n"
1378 "radiusAuthClientServerPortNumber=%d\n"
1379 "radiusAuthClientRoundTripTime=%d\n"
1380 "radiusAuthClientAccessRequests=%u\n"
1381 "radiusAuthClientAccessRetransmissions=%u\n"
1382 "radiusAuthClientAccessAccepts=%u\n"
1383 "radiusAuthClientAccessRejects=%u\n"
1384 "radiusAuthClientAccessChallenges=%u\n"
1385 "radiusAuthClientMalformedAccessResponses=%u\n"
1386 "radiusAuthClientBadAuthenticators=%u\n"
1387 "radiusAuthClientPendingRequests=%u\n"
1388 "radiusAuthClientTimeouts=%u\n"
1389 "radiusAuthClientUnknownTypes=%u\n"
1390 "radiusAuthClientPacketsDropped=%u\n",
1392 hostapd_ip_txt(&serv
->addr
, abuf
, sizeof(abuf
)),
1394 serv
->round_trip_time
,
1396 serv
->retransmissions
,
1397 serv
->access_accepts
,
1398 serv
->access_rejects
,
1399 serv
->access_challenges
,
1400 serv
->malformed_responses
,
1401 serv
->bad_authenticators
,
1404 serv
->unknown_types
,
1405 serv
->packets_dropped
);
1409 static int radius_client_dump_acct_server(char *buf
, size_t buflen
,
1410 struct hostapd_radius_server
*serv
,
1411 struct radius_client_data
*cli
)
1414 struct radius_msg_list
*msg
;
1418 for (msg
= cli
->msgs
; msg
; msg
= msg
->next
) {
1419 if (msg
->msg_type
== RADIUS_ACCT
||
1420 msg
->msg_type
== RADIUS_ACCT_INTERIM
)
1425 return os_snprintf(buf
, buflen
,
1426 "radiusAccServerIndex=%d\n"
1427 "radiusAccServerAddress=%s\n"
1428 "radiusAccClientServerPortNumber=%d\n"
1429 "radiusAccClientRoundTripTime=%d\n"
1430 "radiusAccClientRequests=%u\n"
1431 "radiusAccClientRetransmissions=%u\n"
1432 "radiusAccClientResponses=%u\n"
1433 "radiusAccClientMalformedResponses=%u\n"
1434 "radiusAccClientBadAuthenticators=%u\n"
1435 "radiusAccClientPendingRequests=%u\n"
1436 "radiusAccClientTimeouts=%u\n"
1437 "radiusAccClientUnknownTypes=%u\n"
1438 "radiusAccClientPacketsDropped=%u\n",
1440 hostapd_ip_txt(&serv
->addr
, abuf
, sizeof(abuf
)),
1442 serv
->round_trip_time
,
1444 serv
->retransmissions
,
1446 serv
->malformed_responses
,
1447 serv
->bad_authenticators
,
1450 serv
->unknown_types
,
1451 serv
->packets_dropped
);
1456 * radius_client_get_mib - Get RADIUS client MIB information
1457 * @radius: RADIUS client context from radius_client_init()
1458 * @buf: Buffer for returning MIB data in text format
1459 * @buflen: Maximum buf length in octets
1460 * Returns: Number of octets written into the buffer
1462 int radius_client_get_mib(struct radius_client_data
*radius
, char *buf
,
1465 struct hostapd_radius_servers
*conf
= radius
->conf
;
1467 struct hostapd_radius_server
*serv
;
1470 if (conf
->auth_servers
) {
1471 for (i
= 0; i
< conf
->num_auth_servers
; i
++) {
1472 serv
= &conf
->auth_servers
[i
];
1473 count
+= radius_client_dump_auth_server(
1474 buf
+ count
, buflen
- count
, serv
,
1475 serv
== conf
->auth_server
?
1480 if (conf
->acct_servers
) {
1481 for (i
= 0; i
< conf
->num_acct_servers
; i
++) {
1482 serv
= &conf
->acct_servers
[i
];
1483 count
+= radius_client_dump_acct_server(
1484 buf
+ count
, buflen
- count
, serv
,
1485 serv
== conf
->acct_server
?