Sync mly(4) with FreeBSD.
[dragonfly.git] / contrib / hostapd-0.5.8 / radius_client.c
blob5b00bbeb8577fada3bf97cb3a521202ab83253fe
1 /*
2 * hostapd / RADIUS client
3 * Copyright (c) 2002-2005, 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
10 * license.
12 * See README and COPYING for more details.
15 #include "includes.h"
17 #include "hostapd.h"
18 #include "radius.h"
19 #include "radius_client.h"
20 #include "eloop.h"
22 /* Defaults for RADIUS retransmit values (exponential backoff) */
23 #define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */
24 #define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */
25 #define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts
26 * before entry is removed from retransmit
27 * list */
28 #define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit
29 * list (oldest will be removed, if this
30 * limit is exceeded) */
31 #define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this
32 * many failed retry attempts */
35 struct radius_rx_handler {
36 RadiusRxResult (*handler)(struct radius_msg *msg,
37 struct radius_msg *req,
38 u8 *shared_secret, size_t shared_secret_len,
39 void *data);
40 void *data;
44 /* RADIUS message retransmit list */
45 struct radius_msg_list {
46 u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages
47 * for the same STA. */
48 struct radius_msg *msg;
49 RadiusType msg_type;
50 os_time_t first_try;
51 os_time_t next_try;
52 int attempts;
53 int next_wait;
54 struct os_time last_attempt;
56 u8 *shared_secret;
57 size_t shared_secret_len;
59 /* TODO: server config with failover to backup server(s) */
61 struct radius_msg_list *next;
65 struct radius_client_data {
66 void *ctx;
67 struct hostapd_radius_servers *conf;
69 int auth_serv_sock; /* socket for authentication RADIUS messages */
70 int acct_serv_sock; /* socket for accounting RADIUS messages */
71 int auth_serv_sock6;
72 int acct_serv_sock6;
73 int auth_sock; /* currently used socket */
74 int acct_sock; /* currently used socket */
76 struct radius_rx_handler *auth_handlers;
77 size_t num_auth_handlers;
78 struct radius_rx_handler *acct_handlers;
79 size_t num_acct_handlers;
81 struct radius_msg_list *msgs;
82 size_t num_msgs;
84 u8 next_radius_identifier;
88 static int
89 radius_change_server(struct radius_client_data *radius,
90 struct hostapd_radius_server *nserv,
91 struct hostapd_radius_server *oserv,
92 int sock, int sock6, int auth);
93 static int radius_client_init_acct(struct radius_client_data *radius);
94 static int radius_client_init_auth(struct radius_client_data *radius);
97 static void radius_client_msg_free(struct radius_msg_list *req)
99 radius_msg_free(req->msg);
100 os_free(req->msg);
101 os_free(req);
105 int radius_client_register(struct radius_client_data *radius,
106 RadiusType msg_type,
107 RadiusRxResult (*handler)(struct radius_msg *msg,
108 struct radius_msg *req,
109 u8 *shared_secret,
110 size_t shared_secret_len,
111 void *data),
112 void *data)
114 struct radius_rx_handler **handlers, *newh;
115 size_t *num;
117 if (msg_type == RADIUS_ACCT) {
118 handlers = &radius->acct_handlers;
119 num = &radius->num_acct_handlers;
120 } else {
121 handlers = &radius->auth_handlers;
122 num = &radius->num_auth_handlers;
125 newh = os_realloc(*handlers,
126 (*num + 1) * sizeof(struct radius_rx_handler));
127 if (newh == NULL)
128 return -1;
130 newh[*num].handler = handler;
131 newh[*num].data = data;
132 (*num)++;
133 *handlers = newh;
135 return 0;
139 static void radius_client_handle_send_error(struct radius_client_data *radius,
140 int s, RadiusType msg_type)
142 #ifndef CONFIG_NATIVE_WINDOWS
143 int _errno = errno;
144 perror("send[RADIUS]");
145 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL) {
146 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
147 HOSTAPD_LEVEL_INFO,
148 "Send failed - maybe interface status changed -"
149 " try to connect again");
150 eloop_unregister_read_sock(s);
151 close(s);
152 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
153 radius_client_init_acct(radius);
154 else
155 radius_client_init_auth(radius);
157 #endif /* CONFIG_NATIVE_WINDOWS */
161 static int radius_client_retransmit(struct radius_client_data *radius,
162 struct radius_msg_list *entry,
163 os_time_t now)
165 struct hostapd_radius_servers *conf = radius->conf;
166 int s;
168 if (entry->msg_type == RADIUS_ACCT ||
169 entry->msg_type == RADIUS_ACCT_INTERIM) {
170 s = radius->acct_sock;
171 if (entry->attempts == 0)
172 conf->acct_server->requests++;
173 else {
174 conf->acct_server->timeouts++;
175 conf->acct_server->retransmissions++;
177 } else {
178 s = radius->auth_sock;
179 if (entry->attempts == 0)
180 conf->auth_server->requests++;
181 else {
182 conf->auth_server->timeouts++;
183 conf->auth_server->retransmissions++;
187 /* retransmit; remove entry if too many attempts */
188 entry->attempts++;
189 hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
190 HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
191 entry->msg->hdr->identifier);
193 os_get_time(&entry->last_attempt);
194 if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
195 radius_client_handle_send_error(radius, s, entry->msg_type);
197 entry->next_try = now + entry->next_wait;
198 entry->next_wait *= 2;
199 if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
200 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
201 if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
202 printf("Removing un-ACKed RADIUS message due to too many "
203 "failed retransmit attempts\n");
204 return 1;
207 return 0;
211 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
213 struct radius_client_data *radius = eloop_ctx;
214 struct hostapd_radius_servers *conf = radius->conf;
215 struct os_time now;
216 os_time_t first;
217 struct radius_msg_list *entry, *prev, *tmp;
218 int auth_failover = 0, acct_failover = 0;
219 char abuf[50];
221 entry = radius->msgs;
222 if (!entry)
223 return;
225 os_get_time(&now);
226 first = 0;
228 prev = NULL;
229 while (entry) {
230 if (now.sec >= entry->next_try &&
231 radius_client_retransmit(radius, entry, now.sec)) {
232 if (prev)
233 prev->next = entry->next;
234 else
235 radius->msgs = entry->next;
237 tmp = entry;
238 entry = entry->next;
239 radius_client_msg_free(tmp);
240 radius->num_msgs--;
241 continue;
244 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
245 if (entry->msg_type == RADIUS_ACCT ||
246 entry->msg_type == RADIUS_ACCT_INTERIM)
247 acct_failover++;
248 else
249 auth_failover++;
252 if (first == 0 || entry->next_try < first)
253 first = entry->next_try;
255 prev = entry;
256 entry = entry->next;
259 if (radius->msgs) {
260 if (first < now.sec)
261 first = now.sec;
262 eloop_register_timeout(first - now.sec, 0,
263 radius_client_timer, radius, NULL);
264 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
265 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
266 "retransmit in %ld seconds",
267 (long int) (first - now.sec));
270 if (auth_failover && conf->num_auth_servers > 1) {
271 struct hostapd_radius_server *next, *old;
272 old = conf->auth_server;
273 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
274 HOSTAPD_LEVEL_NOTICE,
275 "No response from Authentication server "
276 "%s:%d - failover",
277 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
278 old->port);
280 for (entry = radius->msgs; entry; entry = entry->next) {
281 if (entry->msg_type == RADIUS_AUTH)
282 old->timeouts++;
285 next = old + 1;
286 if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
287 next = conf->auth_servers;
288 conf->auth_server = next;
289 radius_change_server(radius, next, old,
290 radius->auth_serv_sock,
291 radius->auth_serv_sock6, 1);
294 if (acct_failover && conf->num_acct_servers > 1) {
295 struct hostapd_radius_server *next, *old;
296 old = conf->acct_server;
297 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
298 HOSTAPD_LEVEL_NOTICE,
299 "No response from Accounting server "
300 "%s:%d - failover",
301 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
302 old->port);
304 for (entry = radius->msgs; entry; entry = entry->next) {
305 if (entry->msg_type == RADIUS_ACCT ||
306 entry->msg_type == RADIUS_ACCT_INTERIM)
307 old->timeouts++;
310 next = old + 1;
311 if (next > &conf->acct_servers[conf->num_acct_servers - 1])
312 next = conf->acct_servers;
313 conf->acct_server = next;
314 radius_change_server(radius, next, old,
315 radius->acct_serv_sock,
316 radius->acct_serv_sock6, 0);
321 static void radius_client_update_timeout(struct radius_client_data *radius)
323 struct os_time now;
324 os_time_t first;
325 struct radius_msg_list *entry;
327 eloop_cancel_timeout(radius_client_timer, radius, NULL);
329 if (radius->msgs == NULL) {
330 return;
333 first = 0;
334 for (entry = radius->msgs; entry; entry = entry->next) {
335 if (first == 0 || entry->next_try < first)
336 first = entry->next_try;
339 os_get_time(&now);
340 if (first < now.sec)
341 first = now.sec;
342 eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
343 NULL);
344 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
345 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
346 " %ld seconds\n", (long int) (first - now.sec));
350 static void radius_client_list_add(struct radius_client_data *radius,
351 struct radius_msg *msg,
352 RadiusType msg_type, u8 *shared_secret,
353 size_t shared_secret_len, const u8 *addr)
355 struct radius_msg_list *entry, *prev;
357 if (eloop_terminated()) {
358 /* No point in adding entries to retransmit queue since event
359 * loop has already been terminated. */
360 radius_msg_free(msg);
361 os_free(msg);
362 return;
365 entry = wpa_zalloc(sizeof(*entry));
366 if (entry == NULL) {
367 printf("Failed to add RADIUS packet into retransmit list\n");
368 radius_msg_free(msg);
369 os_free(msg);
370 return;
373 if (addr)
374 os_memcpy(entry->addr, addr, ETH_ALEN);
375 entry->msg = msg;
376 entry->msg_type = msg_type;
377 entry->shared_secret = shared_secret;
378 entry->shared_secret_len = shared_secret_len;
379 os_get_time(&entry->last_attempt);
380 entry->first_try = entry->last_attempt.sec;
381 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
382 entry->attempts = 1;
383 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
384 entry->next = radius->msgs;
385 radius->msgs = entry;
386 radius_client_update_timeout(radius);
388 if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
389 printf("Removing the oldest un-ACKed RADIUS packet due to "
390 "retransmit list limits.\n");
391 prev = NULL;
392 while (entry->next) {
393 prev = entry;
394 entry = entry->next;
396 if (prev) {
397 prev->next = NULL;
398 radius_client_msg_free(entry);
400 } else
401 radius->num_msgs++;
405 static void radius_client_list_del(struct radius_client_data *radius,
406 RadiusType msg_type, const u8 *addr)
408 struct radius_msg_list *entry, *prev, *tmp;
410 if (addr == NULL)
411 return;
413 entry = radius->msgs;
414 prev = NULL;
415 while (entry) {
416 if (entry->msg_type == msg_type &&
417 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
418 if (prev)
419 prev->next = entry->next;
420 else
421 radius->msgs = entry->next;
422 tmp = entry;
423 entry = entry->next;
424 hostapd_logger(radius->ctx, addr,
425 HOSTAPD_MODULE_RADIUS,
426 HOSTAPD_LEVEL_DEBUG,
427 "Removing matching RADIUS message");
428 radius_client_msg_free(tmp);
429 radius->num_msgs--;
430 continue;
432 prev = entry;
433 entry = entry->next;
438 int radius_client_send(struct radius_client_data *radius,
439 struct radius_msg *msg, RadiusType msg_type,
440 const u8 *addr)
442 struct hostapd_radius_servers *conf = radius->conf;
443 u8 *shared_secret;
444 size_t shared_secret_len;
445 char *name;
446 int s, res;
448 if (msg_type == RADIUS_ACCT_INTERIM) {
449 /* Remove any pending interim acct update for the same STA. */
450 radius_client_list_del(radius, msg_type, addr);
453 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
454 shared_secret = conf->acct_server->shared_secret;
455 shared_secret_len = conf->acct_server->shared_secret_len;
456 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
457 name = "accounting";
458 s = radius->acct_sock;
459 conf->acct_server->requests++;
460 } else {
461 shared_secret = conf->auth_server->shared_secret;
462 shared_secret_len = conf->auth_server->shared_secret_len;
463 radius_msg_finish(msg, shared_secret, shared_secret_len);
464 name = "authentication";
465 s = radius->auth_sock;
466 conf->auth_server->requests++;
469 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
470 HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
471 "server", name);
472 if (conf->msg_dumps)
473 radius_msg_dump(msg);
475 res = send(s, msg->buf, msg->buf_used, 0);
476 if (res < 0)
477 radius_client_handle_send_error(radius, s, msg_type);
479 radius_client_list_add(radius, msg, msg_type, shared_secret,
480 shared_secret_len, addr);
482 return res;
486 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
488 struct radius_client_data *radius = eloop_ctx;
489 struct hostapd_radius_servers *conf = radius->conf;
490 RadiusType msg_type = (RadiusType) sock_ctx;
491 int len, roundtrip;
492 unsigned char buf[3000];
493 struct radius_msg *msg;
494 struct radius_rx_handler *handlers;
495 size_t num_handlers, i;
496 struct radius_msg_list *req, *prev_req;
497 struct os_time now;
498 struct hostapd_radius_server *rconf;
499 int invalid_authenticator = 0;
501 if (msg_type == RADIUS_ACCT) {
502 handlers = radius->acct_handlers;
503 num_handlers = radius->num_acct_handlers;
504 rconf = conf->acct_server;
505 } else {
506 handlers = radius->auth_handlers;
507 num_handlers = radius->num_auth_handlers;
508 rconf = conf->auth_server;
511 len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
512 if (len < 0) {
513 perror("recv[RADIUS]");
514 return;
516 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
517 HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
518 "server", len);
519 if (len == sizeof(buf)) {
520 printf("Possibly too long UDP frame for our buffer - "
521 "dropping it\n");
522 return;
525 msg = radius_msg_parse(buf, len);
526 if (msg == NULL) {
527 printf("Parsing incoming RADIUS frame failed\n");
528 rconf->malformed_responses++;
529 return;
532 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
533 HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
534 if (conf->msg_dumps)
535 radius_msg_dump(msg);
537 switch (msg->hdr->code) {
538 case RADIUS_CODE_ACCESS_ACCEPT:
539 rconf->access_accepts++;
540 break;
541 case RADIUS_CODE_ACCESS_REJECT:
542 rconf->access_rejects++;
543 break;
544 case RADIUS_CODE_ACCESS_CHALLENGE:
545 rconf->access_challenges++;
546 break;
547 case RADIUS_CODE_ACCOUNTING_RESPONSE:
548 rconf->responses++;
549 break;
552 prev_req = NULL;
553 req = radius->msgs;
554 while (req) {
555 /* TODO: also match by src addr:port of the packet when using
556 * alternative RADIUS servers (?) */
557 if ((req->msg_type == msg_type ||
558 (req->msg_type == RADIUS_ACCT_INTERIM &&
559 msg_type == RADIUS_ACCT)) &&
560 req->msg->hdr->identifier == msg->hdr->identifier)
561 break;
563 prev_req = req;
564 req = req->next;
567 if (req == NULL) {
568 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
569 HOSTAPD_LEVEL_DEBUG,
570 "No matching RADIUS request found (type=%d "
571 "id=%d) - dropping packet",
572 msg_type, msg->hdr->identifier);
573 goto fail;
576 os_get_time(&now);
577 roundtrip = (now.sec - req->last_attempt.sec) * 100 +
578 (now.usec - req->last_attempt.usec) / 10000;
579 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
580 HOSTAPD_LEVEL_DEBUG,
581 "Received RADIUS packet matched with a pending "
582 "request, round trip time %d.%02d sec",
583 roundtrip / 100, roundtrip % 100);
584 rconf->round_trip_time = roundtrip;
586 /* Remove ACKed RADIUS packet from retransmit list */
587 if (prev_req)
588 prev_req->next = req->next;
589 else
590 radius->msgs = req->next;
591 radius->num_msgs--;
593 for (i = 0; i < num_handlers; i++) {
594 RadiusRxResult res;
595 res = handlers[i].handler(msg, req->msg, req->shared_secret,
596 req->shared_secret_len,
597 handlers[i].data);
598 switch (res) {
599 case RADIUS_RX_PROCESSED:
600 radius_msg_free(msg);
601 os_free(msg);
602 /* continue */
603 case RADIUS_RX_QUEUED:
604 radius_client_msg_free(req);
605 return;
606 case RADIUS_RX_INVALID_AUTHENTICATOR:
607 invalid_authenticator++;
608 /* continue */
609 case RADIUS_RX_UNKNOWN:
610 /* continue with next handler */
611 break;
615 if (invalid_authenticator)
616 rconf->bad_authenticators++;
617 else
618 rconf->unknown_types++;
619 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
620 HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
621 "(type=%d code=%d id=%d)%s - dropping packet",
622 msg_type, msg->hdr->code, msg->hdr->identifier,
623 invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
624 "");
625 radius_client_msg_free(req);
627 fail:
628 radius_msg_free(msg);
629 os_free(msg);
633 u8 radius_client_get_id(struct radius_client_data *radius)
635 struct radius_msg_list *entry, *prev, *_remove;
636 u8 id = radius->next_radius_identifier++;
638 /* remove entries with matching id from retransmit list to avoid
639 * using new reply from the RADIUS server with an old request */
640 entry = radius->msgs;
641 prev = NULL;
642 while (entry) {
643 if (entry->msg->hdr->identifier == id) {
644 hostapd_logger(radius->ctx, entry->addr,
645 HOSTAPD_MODULE_RADIUS,
646 HOSTAPD_LEVEL_DEBUG,
647 "Removing pending RADIUS message, "
648 "since its id (%d) is reused", id);
649 if (prev)
650 prev->next = entry->next;
651 else
652 radius->msgs = entry->next;
653 _remove = entry;
654 } else {
655 _remove = NULL;
656 prev = entry;
658 entry = entry->next;
660 if (_remove)
661 radius_client_msg_free(_remove);
664 return id;
668 void radius_client_flush(struct radius_client_data *radius, int only_auth)
670 struct radius_msg_list *entry, *prev, *tmp;
672 if (!radius)
673 return;
675 prev = NULL;
676 entry = radius->msgs;
678 while (entry) {
679 if (!only_auth || entry->msg_type == RADIUS_AUTH) {
680 if (prev)
681 prev->next = entry->next;
682 else
683 radius->msgs = entry->next;
685 tmp = entry;
686 entry = entry->next;
687 radius_client_msg_free(tmp);
688 radius->num_msgs--;
689 } else {
690 prev = entry;
691 entry = entry->next;
695 if (radius->msgs == NULL)
696 eloop_cancel_timeout(radius_client_timer, radius, NULL);
700 void radius_client_update_acct_msgs(struct radius_client_data *radius,
701 u8 *shared_secret,
702 size_t shared_secret_len)
704 struct radius_msg_list *entry;
706 if (!radius)
707 return;
709 for (entry = radius->msgs; entry; entry = entry->next) {
710 if (entry->msg_type == RADIUS_ACCT) {
711 entry->shared_secret = shared_secret;
712 entry->shared_secret_len = shared_secret_len;
713 radius_msg_finish_acct(entry->msg, shared_secret,
714 shared_secret_len);
720 static int
721 radius_change_server(struct radius_client_data *radius,
722 struct hostapd_radius_server *nserv,
723 struct hostapd_radius_server *oserv,
724 int sock, int sock6, int auth)
726 struct sockaddr_in serv;
727 #ifdef CONFIG_IPV6
728 struct sockaddr_in6 serv6;
729 #endif /* CONFIG_IPV6 */
730 struct sockaddr *addr;
731 socklen_t addrlen;
732 char abuf[50];
733 int sel_sock;
734 struct radius_msg_list *entry;
736 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
737 HOSTAPD_LEVEL_INFO,
738 "%s server %s:%d",
739 auth ? "Authentication" : "Accounting",
740 hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
741 nserv->port);
743 if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
744 os_memcmp(nserv->shared_secret, oserv->shared_secret,
745 nserv->shared_secret_len) != 0) {
746 /* Pending RADIUS packets used different shared secret, so
747 * they need to be modified. Update accounting message
748 * authenticators here. Authentication messages are removed
749 * since they would require more changes and the new RADIUS
750 * server may not be prepared to receive them anyway due to
751 * missing state information. Client will likely retry
752 * authentication, so this should not be an issue. */
753 if (auth)
754 radius_client_flush(radius, 1);
755 else {
756 radius_client_update_acct_msgs(
757 radius, nserv->shared_secret,
758 nserv->shared_secret_len);
762 /* Reset retry counters for the new server */
763 for (entry = radius->msgs; entry; entry = entry->next) {
764 if ((auth && entry->msg_type != RADIUS_AUTH) ||
765 (!auth && entry->msg_type != RADIUS_ACCT))
766 continue;
767 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
768 entry->attempts = 0;
769 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
772 if (radius->msgs) {
773 eloop_cancel_timeout(radius_client_timer, radius, NULL);
774 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
775 radius_client_timer, radius, NULL);
778 switch (nserv->addr.af) {
779 case AF_INET:
780 os_memset(&serv, 0, sizeof(serv));
781 serv.sin_family = AF_INET;
782 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
783 serv.sin_port = htons(nserv->port);
784 addr = (struct sockaddr *) &serv;
785 addrlen = sizeof(serv);
786 sel_sock = sock;
787 break;
788 #ifdef CONFIG_IPV6
789 case AF_INET6:
790 os_memset(&serv6, 0, sizeof(serv6));
791 serv6.sin6_family = AF_INET6;
792 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
793 sizeof(struct in6_addr));
794 serv6.sin6_port = htons(nserv->port);
795 addr = (struct sockaddr *) &serv6;
796 addrlen = sizeof(serv6);
797 sel_sock = sock6;
798 break;
799 #endif /* CONFIG_IPV6 */
800 default:
801 return -1;
804 if (connect(sel_sock, addr, addrlen) < 0) {
805 perror("connect[radius]");
806 return -1;
809 if (auth)
810 radius->auth_sock = sel_sock;
811 else
812 radius->acct_sock = sel_sock;
814 return 0;
818 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
820 struct radius_client_data *radius = eloop_ctx;
821 struct hostapd_radius_servers *conf = radius->conf;
822 struct hostapd_radius_server *oserv;
824 if (radius->auth_sock >= 0 && conf->auth_servers &&
825 conf->auth_server != conf->auth_servers) {
826 oserv = conf->auth_server;
827 conf->auth_server = conf->auth_servers;
828 radius_change_server(radius, conf->auth_server, oserv,
829 radius->auth_serv_sock,
830 radius->auth_serv_sock6, 1);
833 if (radius->acct_sock >= 0 && conf->acct_servers &&
834 conf->acct_server != conf->acct_servers) {
835 oserv = conf->acct_server;
836 conf->acct_server = conf->acct_servers;
837 radius_change_server(radius, conf->acct_server, oserv,
838 radius->acct_serv_sock,
839 radius->acct_serv_sock6, 0);
842 if (conf->retry_primary_interval)
843 eloop_register_timeout(conf->retry_primary_interval, 0,
844 radius_retry_primary_timer, radius,
845 NULL);
849 static int radius_client_init_auth(struct radius_client_data *radius)
851 struct hostapd_radius_servers *conf = radius->conf;
852 int ok = 0;
854 radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
855 if (radius->auth_serv_sock < 0)
856 perror("socket[PF_INET,SOCK_DGRAM]");
857 else
858 ok++;
860 #ifdef CONFIG_IPV6
861 radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
862 if (radius->auth_serv_sock6 < 0)
863 perror("socket[PF_INET6,SOCK_DGRAM]");
864 else
865 ok++;
866 #endif /* CONFIG_IPV6 */
868 if (ok == 0)
869 return -1;
871 radius_change_server(radius, conf->auth_server, NULL,
872 radius->auth_serv_sock, radius->auth_serv_sock6,
875 if (radius->auth_serv_sock >= 0 &&
876 eloop_register_read_sock(radius->auth_serv_sock,
877 radius_client_receive, radius,
878 (void *) RADIUS_AUTH)) {
879 printf("Could not register read socket for authentication "
880 "server\n");
881 return -1;
884 #ifdef CONFIG_IPV6
885 if (radius->auth_serv_sock6 >= 0 &&
886 eloop_register_read_sock(radius->auth_serv_sock6,
887 radius_client_receive, radius,
888 (void *) RADIUS_AUTH)) {
889 printf("Could not register read socket for authentication "
890 "server\n");
891 return -1;
893 #endif /* CONFIG_IPV6 */
895 return 0;
899 static int radius_client_init_acct(struct radius_client_data *radius)
901 struct hostapd_radius_servers *conf = radius->conf;
902 int ok = 0;
904 radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
905 if (radius->acct_serv_sock < 0)
906 perror("socket[PF_INET,SOCK_DGRAM]");
907 else
908 ok++;
910 #ifdef CONFIG_IPV6
911 radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
912 if (radius->acct_serv_sock6 < 0)
913 perror("socket[PF_INET6,SOCK_DGRAM]");
914 else
915 ok++;
916 #endif /* CONFIG_IPV6 */
918 if (ok == 0)
919 return -1;
921 radius_change_server(radius, conf->acct_server, NULL,
922 radius->acct_serv_sock, radius->acct_serv_sock6,
925 if (radius->acct_serv_sock >= 0 &&
926 eloop_register_read_sock(radius->acct_serv_sock,
927 radius_client_receive, radius,
928 (void *) RADIUS_ACCT)) {
929 printf("Could not register read socket for accounting "
930 "server\n");
931 return -1;
934 #ifdef CONFIG_IPV6
935 if (radius->acct_serv_sock6 >= 0 &&
936 eloop_register_read_sock(radius->acct_serv_sock6,
937 radius_client_receive, radius,
938 (void *) RADIUS_ACCT)) {
939 printf("Could not register read socket for accounting "
940 "server\n");
941 return -1;
943 #endif /* CONFIG_IPV6 */
945 return 0;
949 struct radius_client_data *
950 radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
952 struct radius_client_data *radius;
954 radius = wpa_zalloc(sizeof(struct radius_client_data));
955 if (radius == NULL)
956 return NULL;
958 radius->ctx = ctx;
959 radius->conf = conf;
960 radius->auth_serv_sock = radius->acct_serv_sock =
961 radius->auth_serv_sock6 = radius->acct_serv_sock6 =
962 radius->auth_sock = radius->acct_sock = -1;
964 if (conf->auth_server && radius_client_init_auth(radius)) {
965 radius_client_deinit(radius);
966 return NULL;
969 if (conf->acct_server && radius_client_init_acct(radius)) {
970 radius_client_deinit(radius);
971 return NULL;
974 if (conf->retry_primary_interval)
975 eloop_register_timeout(conf->retry_primary_interval, 0,
976 radius_retry_primary_timer, radius,
977 NULL);
979 return radius;
983 void radius_client_deinit(struct radius_client_data *radius)
985 if (!radius)
986 return;
988 if (radius->auth_serv_sock >= 0)
989 eloop_unregister_read_sock(radius->auth_serv_sock);
990 if (radius->acct_serv_sock >= 0)
991 eloop_unregister_read_sock(radius->acct_serv_sock);
993 eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
995 radius_client_flush(radius, 0);
996 os_free(radius->auth_handlers);
997 os_free(radius->acct_handlers);
998 os_free(radius);
1002 void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
1004 struct radius_msg_list *entry, *prev, *tmp;
1006 prev = NULL;
1007 entry = radius->msgs;
1008 while (entry) {
1009 if (entry->msg_type == RADIUS_AUTH &&
1010 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1011 hostapd_logger(radius->ctx, addr,
1012 HOSTAPD_MODULE_RADIUS,
1013 HOSTAPD_LEVEL_DEBUG,
1014 "Removing pending RADIUS authentication"
1015 " message for removed client");
1017 if (prev)
1018 prev->next = entry->next;
1019 else
1020 radius->msgs = entry->next;
1022 tmp = entry;
1023 entry = entry->next;
1024 radius_client_msg_free(tmp);
1025 radius->num_msgs--;
1026 continue;
1029 prev = entry;
1030 entry = entry->next;
1035 static int radius_client_dump_auth_server(char *buf, size_t buflen,
1036 struct hostapd_radius_server *serv,
1037 struct radius_client_data *cli)
1039 int pending = 0;
1040 struct radius_msg_list *msg;
1041 char abuf[50];
1043 if (cli) {
1044 for (msg = cli->msgs; msg; msg = msg->next) {
1045 if (msg->msg_type == RADIUS_AUTH)
1046 pending++;
1050 return os_snprintf(buf, buflen,
1051 "radiusAuthServerIndex=%d\n"
1052 "radiusAuthServerAddress=%s\n"
1053 "radiusAuthClientServerPortNumber=%d\n"
1054 "radiusAuthClientRoundTripTime=%d\n"
1055 "radiusAuthClientAccessRequests=%u\n"
1056 "radiusAuthClientAccessRetransmissions=%u\n"
1057 "radiusAuthClientAccessAccepts=%u\n"
1058 "radiusAuthClientAccessRejects=%u\n"
1059 "radiusAuthClientAccessChallenges=%u\n"
1060 "radiusAuthClientMalformedAccessResponses=%u\n"
1061 "radiusAuthClientBadAuthenticators=%u\n"
1062 "radiusAuthClientPendingRequests=%u\n"
1063 "radiusAuthClientTimeouts=%u\n"
1064 "radiusAuthClientUnknownTypes=%u\n"
1065 "radiusAuthClientPacketsDropped=%u\n",
1066 serv->index,
1067 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1068 serv->port,
1069 serv->round_trip_time,
1070 serv->requests,
1071 serv->retransmissions,
1072 serv->access_accepts,
1073 serv->access_rejects,
1074 serv->access_challenges,
1075 serv->malformed_responses,
1076 serv->bad_authenticators,
1077 pending,
1078 serv->timeouts,
1079 serv->unknown_types,
1080 serv->packets_dropped);
1084 static int radius_client_dump_acct_server(char *buf, size_t buflen,
1085 struct hostapd_radius_server *serv,
1086 struct radius_client_data *cli)
1088 int pending = 0;
1089 struct radius_msg_list *msg;
1090 char abuf[50];
1092 if (cli) {
1093 for (msg = cli->msgs; msg; msg = msg->next) {
1094 if (msg->msg_type == RADIUS_ACCT ||
1095 msg->msg_type == RADIUS_ACCT_INTERIM)
1096 pending++;
1100 return os_snprintf(buf, buflen,
1101 "radiusAccServerIndex=%d\n"
1102 "radiusAccServerAddress=%s\n"
1103 "radiusAccClientServerPortNumber=%d\n"
1104 "radiusAccClientRoundTripTime=%d\n"
1105 "radiusAccClientRequests=%u\n"
1106 "radiusAccClientRetransmissions=%u\n"
1107 "radiusAccClientResponses=%u\n"
1108 "radiusAccClientMalformedResponses=%u\n"
1109 "radiusAccClientBadAuthenticators=%u\n"
1110 "radiusAccClientPendingRequests=%u\n"
1111 "radiusAccClientTimeouts=%u\n"
1112 "radiusAccClientUnknownTypes=%u\n"
1113 "radiusAccClientPacketsDropped=%u\n",
1114 serv->index,
1115 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1116 serv->port,
1117 serv->round_trip_time,
1118 serv->requests,
1119 serv->retransmissions,
1120 serv->responses,
1121 serv->malformed_responses,
1122 serv->bad_authenticators,
1123 pending,
1124 serv->timeouts,
1125 serv->unknown_types,
1126 serv->packets_dropped);
1130 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1131 size_t buflen)
1133 struct hostapd_radius_servers *conf = radius->conf;
1134 int i;
1135 struct hostapd_radius_server *serv;
1136 int count = 0;
1138 if (conf->auth_servers) {
1139 for (i = 0; i < conf->num_auth_servers; i++) {
1140 serv = &conf->auth_servers[i];
1141 count += radius_client_dump_auth_server(
1142 buf + count, buflen - count, serv,
1143 serv == conf->auth_server ?
1144 radius : NULL);
1148 if (conf->acct_servers) {
1149 for (i = 0; i < conf->num_acct_servers; i++) {
1150 serv = &conf->acct_servers[i];
1151 count += radius_client_dump_acct_server(
1152 buf + count, buflen - count, serv,
1153 serv == conf->acct_server ?
1154 radius : NULL);
1158 return count;
1162 static int radius_servers_diff(struct hostapd_radius_server *nserv,
1163 struct hostapd_radius_server *oserv,
1164 int num)
1166 int i;
1168 for (i = 0; i < num; i++) {
1169 if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) ||
1170 nserv[i].port != oserv[i].port ||
1171 nserv[i].shared_secret_len != oserv[i].shared_secret_len ||
1172 memcmp(nserv[i].shared_secret, oserv[i].shared_secret,
1173 nserv[i].shared_secret_len) != 0)
1174 return 1;
1177 return 0;
1181 struct radius_client_data *
1182 radius_client_reconfig(struct radius_client_data *old, void *ctx,
1183 struct hostapd_radius_servers *oldconf,
1184 struct hostapd_radius_servers *newconf)
1186 radius_client_flush(old, 0);
1188 if (newconf->retry_primary_interval !=
1189 oldconf->retry_primary_interval ||
1190 newconf->num_auth_servers != oldconf->num_auth_servers ||
1191 newconf->num_acct_servers != oldconf->num_acct_servers ||
1192 radius_servers_diff(newconf->auth_servers, oldconf->auth_servers,
1193 newconf->num_auth_servers) ||
1194 radius_servers_diff(newconf->acct_servers, oldconf->acct_servers,
1195 newconf->num_acct_servers)) {
1196 hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS,
1197 HOSTAPD_LEVEL_DEBUG,
1198 "Reconfiguring RADIUS client");
1199 radius_client_deinit(old);
1200 return radius_client_init(ctx, newconf);
1203 return old;