1 /*
2 * RADIUS client
3 * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
4 *
5 * This software may be distributed under the terms of the BSD license.
6 * See README for more details.
7 */
8
9 #include "includes.h"
10
11 #include "common.h"
12 #include "radius.h"
13 #include "radius_client.h"
14 #include "eloop.h"
15
16 /* Defaults for RADIUS retransmit values (exponential backoff) */
17
18 /**
19 * RADIUS_CLIENT_FIRST_WAIT - RADIUS client timeout for first retry in seconds
20 */
21 #define RADIUS_CLIENT_FIRST_WAIT 3
22
23 /**
24 * RADIUS_CLIENT_MAX_WAIT - RADIUS client maximum retry timeout in seconds
25 */
26 #define RADIUS_CLIENT_MAX_WAIT 120
27
28 /**
29 * RADIUS_CLIENT_MAX_RETRIES - RADIUS client maximum retries
30 *
31 * Maximum number of retransmit attempts before the entry is removed from
32 * retransmit list.
33 */
34 #define RADIUS_CLIENT_MAX_RETRIES 10
35
36 /**
37 * RADIUS_CLIENT_MAX_ENTRIES - RADIUS client maximum pending messages
38 *
39 * Maximum number of entries in retransmit list (oldest entries will be
40 * removed, if this limit is exceeded).
41 */
42 #define RADIUS_CLIENT_MAX_ENTRIES 30
43
44 /**
45 * RADIUS_CLIENT_NUM_FAILOVER - RADIUS client failover point
46 *
47 * The number of failed retry attempts after which the RADIUS server will be
48 * changed (if one of more backup servers are configured).
49 */
50 #define RADIUS_CLIENT_NUM_FAILOVER 4
51
52
53 /**
54 * struct radius_rx_handler - RADIUS client RX handler
55 *
56 * This data structure is used internally inside the RADIUS client module to
57 * store registered RX handlers. These handlers are registered by calls to
58 * radius_client_register() and unregistered when the RADIUS client is
59 * deinitialized with a call to radius_client_deinit().
60 */
61 struct radius_rx_handler {
62 /**
63 * handler - Received RADIUS message handler
64 */
65 RadiusRxResult (*handler)(struct radius_msg *msg,
66 struct radius_msg *req,
67 const u8 *shared_secret,
68 size_t shared_secret_len,
69 void *data);
70
71 /**
72 * data - Context data for the handler
73 */
74 void *data;
75 };
76
77
78 /**
79 * struct radius_msg_list - RADIUS client message retransmit list
80 *
81 * This data structure is used internally inside the RADIUS client module to
82 * store pending RADIUS requests that may still need to be retransmitted.
83 */
84 struct radius_msg_list {
85 /**
86 * addr - STA/client address
87 *
88 * This is used to find RADIUS messages for the same STA.
89 */
90 u8 addr[ETH_ALEN];
91
92 /**
93 * msg - RADIUS message
94 */
95 struct radius_msg *msg;
96
97 /**
98 * msg_type - Message type
99 */
100 RadiusType msg_type;
101
102 /**
103 * first_try - Time of the first transmission attempt
104 */
105 os_time_t first_try;
106
107 /**
108 * next_try - Time for the next transmission attempt
109 */
110 os_time_t next_try;
111
112 /**
113 * attempts - Number of transmission attempts
114 */
115 int attempts;
116
117 /**
118 * next_wait - Next retransmission wait time in seconds
119 */
120 int next_wait;
121
122 /**
123 * last_attempt - Time of the last transmission attempt
124 */
125 struct os_reltime last_attempt;
126
127 /**
128 * shared_secret - Shared secret with the target RADIUS server
129 */
130 const u8 *shared_secret;
131
132 /**
133 * shared_secret_len - shared_secret length in octets
134 */
135 size_t shared_secret_len;
136
137 /* TODO: server config with failover to backup server(s) */
138
139 /**
140 * next - Next message in the list
141 */
142 struct radius_msg_list *next;
143 };
144
145
146 /**
147 * struct radius_client_data - Internal RADIUS client data
148 *
149 * This data structure is used internally inside the RADIUS client module.
150 * External users allocate this by calling radius_client_init() and free it by
151 * calling radius_client_deinit(). The pointer to this opaque data is used in
152 * calls to other functions as an identifier for the RADIUS client instance.
153 */
154 struct radius_client_data {
155 /**
156 * ctx - Context pointer for hostapd_logger() callbacks
157 */
158 void *ctx;
159
160 /**
161 * conf - RADIUS client configuration (list of RADIUS servers to use)
162 */
163 struct hostapd_radius_servers *conf;
164
165 /**
166 * auth_serv_sock - IPv4 socket for RADIUS authentication messages
167 */
168 int auth_serv_sock;
169
170 /**
171 * acct_serv_sock - IPv4 socket for RADIUS accounting messages
172 */
173 int acct_serv_sock;
174
175 /**
176 * auth_serv_sock6 - IPv6 socket for RADIUS authentication messages
177 */
178 int auth_serv_sock6;
179
180 /**
181 * acct_serv_sock6 - IPv6 socket for RADIUS accounting messages
182 */
183 int acct_serv_sock6;
184
185 /**
186 * auth_sock - Currently used socket for RADIUS authentication server
187 */
188 int auth_sock;
189
190 /**
191 * acct_sock - Currently used socket for RADIUS accounting server
192 */
193 int acct_sock;
194
195 /**
196 * auth_handlers - Authentication message handlers
197 */
198 struct radius_rx_handler *auth_handlers;
199
200 /**
201 * num_auth_handlers - Number of handlers in auth_handlers
202 */
203 size_t num_auth_handlers;
204
205 /**
206 * acct_handlers - Accounting message handlers
207 */
208 struct radius_rx_handler *acct_handlers;
209
210 /**
211 * num_acct_handlers - Number of handlers in acct_handlers
212 */
213 size_t num_acct_handlers;
214
215 /**
216 * msgs - Pending outgoing RADIUS messages
217 */
218 struct radius_msg_list *msgs;
219
220 /**
221 * num_msgs - Number of pending messages in the msgs list
222 */
223 size_t num_msgs;
224
225 /**
226 * next_radius_identifier - Next RADIUS message identifier to use
227 */
228 u8 next_radius_identifier;
229
230 /**
231 * interim_error_cb - Interim accounting error callback
232 */
233 void (*interim_error_cb)(const u8 *addr, void *ctx);
234
235 /**
236 * interim_error_cb_ctx - interim_error_cb() context data
237 */
238 void *interim_error_cb_ctx;
239 };
240
241
242 static int
243 radius_change_server(struct radius_client_data *radius,
244 struct hostapd_radius_server *nserv,
245 struct hostapd_radius_server *oserv,
246 int sock, int sock6, int auth);
247 static int radius_client_init_acct(struct radius_client_data *radius);
248 static int radius_client_init_auth(struct radius_client_data *radius);
249 static void radius_client_auth_failover(struct radius_client_data *radius);
250 static void radius_client_acct_failover(struct radius_client_data *radius);
251
252
radius_client_msg_free(struct radius_msg_list * req)253 static void radius_client_msg_free(struct radius_msg_list *req)
254 {
255 radius_msg_free(req->msg);
256 os_free(req);
257 }
258
259
260 /**
261 * radius_client_register - Register a RADIUS client RX handler
262 * @radius: RADIUS client context from radius_client_init()
263 * @msg_type: RADIUS client type (RADIUS_AUTH or RADIUS_ACCT)
264 * @handler: Handler for received RADIUS messages
265 * @data: Context pointer for handler callbacks
266 * Returns: 0 on success, -1 on failure
267 *
268 * This function is used to register a handler for processing received RADIUS
269 * authentication and accounting messages. The handler() callback function will
270 * be called whenever a RADIUS message is received from the active server.
271 *
272 * There can be multiple registered RADIUS message handlers. The handlers will
273 * be called in order until one of them indicates that it has processed or
274 * queued the message.
275 */
radius_client_register(struct radius_client_data * radius,RadiusType msg_type,RadiusRxResult (* handler)(struct radius_msg * msg,struct radius_msg * req,const u8 * shared_secret,size_t shared_secret_len,void * data),void * data)276 int radius_client_register(struct radius_client_data *radius,
277 RadiusType msg_type,
278 RadiusRxResult (*handler)(struct radius_msg *msg,
279 struct radius_msg *req,
280 const u8 *shared_secret,
281 size_t shared_secret_len,
282 void *data),
283 void *data)
284 {
285 struct radius_rx_handler **handlers, *newh;
286 size_t *num;
287
288 if (msg_type == RADIUS_ACCT) {
289 handlers = &radius->acct_handlers;
290 num = &radius->num_acct_handlers;
291 } else {
292 handlers = &radius->auth_handlers;
293 num = &radius->num_auth_handlers;
294 }
295
296 newh = os_realloc_array(*handlers, *num + 1,
297 sizeof(struct radius_rx_handler));
298 if (newh == NULL)
299 return -1;
300
301 newh[*num].handler = handler;
302 newh[*num].data = data;
303 (*num)++;
304 *handlers = newh;
305
306 return 0;
307 }
308
309
310 /**
311 * radius_client_set_interim_erro_cb - Register an interim acct error callback
312 * @radius: RADIUS client context from radius_client_init()
313 * @addr: Station address from the failed message
314 * @cb: Handler for interim accounting errors
315 * @ctx: Context pointer for handler callbacks
316 *
317 * This function is used to register a handler for processing failed
318 * transmission attempts of interim accounting update messages.
319 */
radius_client_set_interim_error_cb(struct radius_client_data * radius,void (* cb)(const u8 * addr,void * ctx),void * ctx)320 void radius_client_set_interim_error_cb(struct radius_client_data *radius,
321 void (*cb)(const u8 *addr, void *ctx),
322 void *ctx)
323 {
324 radius->interim_error_cb = cb;
325 radius->interim_error_cb_ctx = ctx;
326 }
327
328
329 /*
330 * Returns >0 if message queue was flushed (i.e., the message that triggered
331 * the error is not available anymore)
332 */
radius_client_handle_send_error(struct radius_client_data * radius,int s,RadiusType msg_type)333 static int radius_client_handle_send_error(struct radius_client_data *radius,
334 int s, RadiusType msg_type)
335 {
336 #ifndef CONFIG_NATIVE_WINDOWS
337 int _errno = errno;
338 wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
339 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
340 _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
341 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
342 HOSTAPD_LEVEL_INFO,
343 "Send failed - maybe interface status changed -"
344 " try to connect again");
345 if (msg_type == RADIUS_ACCT ||
346 msg_type == RADIUS_ACCT_INTERIM) {
347 radius_client_init_acct(radius);
348 return 0;
349 } else {
350 radius_client_init_auth(radius);
351 return 1;
352 }
353 }
354 #endif /* CONFIG_NATIVE_WINDOWS */
355
356 return 0;
357 }
358
359
radius_client_retransmit(struct radius_client_data * radius,struct radius_msg_list * entry,os_time_t now)360 static int radius_client_retransmit(struct radius_client_data *radius,
361 struct radius_msg_list *entry,
362 os_time_t now)
363 {
364 struct hostapd_radius_servers *conf = radius->conf;
365 int s;
366 struct wpabuf *buf;
367 size_t prev_num_msgs;
368 u8 *acct_delay_time;
369 size_t acct_delay_time_len;
370
371 if (entry->msg_type == RADIUS_ACCT ||
372 entry->msg_type == RADIUS_ACCT_INTERIM) {
373 if (radius->acct_sock < 0)
374 radius_client_init_acct(radius);
375 if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
376 prev_num_msgs = radius->num_msgs;
377 radius_client_acct_failover(radius);
378 if (prev_num_msgs != radius->num_msgs)
379 return 0;
380 }
381 s = radius->acct_sock;
382 if (entry->attempts == 0)
383 conf->acct_server->requests++;
384 else {
385 conf->acct_server->timeouts++;
386 conf->acct_server->retransmissions++;
387 }
388 } else {
389 if (radius->auth_sock < 0)
390 radius_client_init_auth(radius);
391 if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
392 prev_num_msgs = radius->num_msgs;
393 radius_client_auth_failover(radius);
394 if (prev_num_msgs != radius->num_msgs)
395 return 0;
396 }
397 s = radius->auth_sock;
398 if (entry->attempts == 0)
399 conf->auth_server->requests++;
400 else {
401 conf->auth_server->timeouts++;
402 conf->auth_server->retransmissions++;
403 }
404 }
405
406 if (entry->msg_type == RADIUS_ACCT_INTERIM) {
407 wpa_printf(MSG_DEBUG,
408 "RADIUS: Failed to transmit interim accounting update to "
409 MACSTR " - drop message and request a new update",
410 MAC2STR(entry->addr));
411 if (radius->interim_error_cb)
412 radius->interim_error_cb(entry->addr,
413 radius->interim_error_cb_ctx);
414 return 1;
415 }
416
417 if (s < 0) {
418 wpa_printf(MSG_INFO,
419 "RADIUS: No valid socket for retransmission");
420 return 1;
421 }
422
423 if (entry->msg_type == RADIUS_ACCT &&
424 radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
425 &acct_delay_time, &acct_delay_time_len,
426 NULL) == 0 &&
427 acct_delay_time_len == 4) {
428 struct radius_hdr *hdr;
429 u32 delay_time;
430
431 /*
432 * Need to assign a new identifier since attribute contents
433 * changes.
434 */
435 hdr = radius_msg_get_hdr(entry->msg);
436 hdr->identifier = radius_client_get_id(radius);
437
438 /* Update Acct-Delay-Time to show wait time in queue */
439 delay_time = now - entry->first_try;
440 WPA_PUT_BE32(acct_delay_time, delay_time);
441
442 wpa_printf(MSG_DEBUG,
443 "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
444 delay_time);
445 radius_msg_finish_acct(entry->msg, entry->shared_secret,
446 entry->shared_secret_len);
447 if (radius->conf->msg_dumps)
448 radius_msg_dump(entry->msg);
449 }
450
451 /* retransmit; remove entry if too many attempts */
452 entry->attempts++;
453 hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
454 HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
455 radius_msg_get_hdr(entry->msg)->identifier);
456
457 os_get_reltime(&entry->last_attempt);
458 buf = radius_msg_get_buf(entry->msg);
459 if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
460 if (radius_client_handle_send_error(radius, s, entry->msg_type)
461 > 0)
462 return 0;
463 }
464
465 entry->next_try = now + entry->next_wait;
466 entry->next_wait *= 2;
467 if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
468 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
469 if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
470 wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
471 return 1;
472 }
473
474 return 0;
475 }
476
477
radius_client_timer(void * eloop_ctx,void * timeout_ctx)478 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
479 {
480 struct radius_client_data *radius = eloop_ctx;
481 struct os_reltime now;
482 os_time_t first;
483 struct radius_msg_list *entry, *prev, *tmp;
484 int auth_failover = 0, acct_failover = 0;
485 size_t prev_num_msgs;
486 int s;
487
488 entry = radius->msgs;
489 if (!entry)
490 return;
491
492 os_get_reltime(&now);
493 first = 0;
494
495 prev = NULL;
496 while (entry) {
497 prev_num_msgs = radius->num_msgs;
498 if (now.sec >= entry->next_try &&
499 radius_client_retransmit(radius, entry, now.sec)) {
500 if (prev)
501 prev->next = entry->next;
502 else
503 radius->msgs = entry->next;
504
505 tmp = entry;
506 entry = entry->next;
507 radius_client_msg_free(tmp);
508 radius->num_msgs--;
509 continue;
510 }
511
512 if (prev_num_msgs != radius->num_msgs) {
513 wpa_printf(MSG_DEBUG,
514 "RADIUS: Message removed from queue - restart from beginning");
515 entry = radius->msgs;
516 prev = NULL;
517 continue;
518 }
519
520 s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
521 radius->acct_sock;
522 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
523 (s < 0 && entry->attempts > 0)) {
524 if (entry->msg_type == RADIUS_ACCT ||
525 entry->msg_type == RADIUS_ACCT_INTERIM)
526 acct_failover++;
527 else
528 auth_failover++;
529 }
530
531 if (first == 0 || entry->next_try < first)
532 first = entry->next_try;
533
534 prev = entry;
535 entry = entry->next;
536 }
537
538 if (radius->msgs) {
539 if (first < now.sec)
540 first = now.sec;
541 eloop_register_timeout(first - now.sec, 0,
542 radius_client_timer, radius, NULL);
543 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
544 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
545 "retransmit in %ld seconds",
546 (long int) (first - now.sec));
547 }
548
549 if (auth_failover)
550 radius_client_auth_failover(radius);
551
552 if (acct_failover)
553 radius_client_acct_failover(radius);
554 }
555
556
radius_client_auth_failover(struct radius_client_data * radius)557 static void radius_client_auth_failover(struct radius_client_data *radius)
558 {
559 struct hostapd_radius_servers *conf = radius->conf;
560 struct hostapd_radius_server *next, *old;
561 struct radius_msg_list *entry;
562 char abuf[50];
563
564 old = conf->auth_server;
565 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
566 HOSTAPD_LEVEL_NOTICE,
567 "No response from Authentication server %s:%d - failover",
568 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
569 old->port);
570
571 for (entry = radius->msgs; entry; entry = entry->next) {
572 if (entry->msg_type == RADIUS_AUTH)
573 old->timeouts++;
574 }
575
576 next = old + 1;
577 if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
578 next = conf->auth_servers;
579 conf->auth_server = next;
580 radius_change_server(radius, next, old,
581 radius->auth_serv_sock,
582 radius->auth_serv_sock6, 1);
583 }
584
585
radius_client_acct_failover(struct radius_client_data * radius)586 static void radius_client_acct_failover(struct radius_client_data *radius)
587 {
588 struct hostapd_radius_servers *conf = radius->conf;
589 struct hostapd_radius_server *next, *old;
590 struct radius_msg_list *entry;
591 char abuf[50];
592
593 old = conf->acct_server;
594 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
595 HOSTAPD_LEVEL_NOTICE,
596 "No response from Accounting server %s:%d - failover",
597 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
598 old->port);
599
600 for (entry = radius->msgs; entry; entry = entry->next) {
601 if (entry->msg_type == RADIUS_ACCT ||
602 entry->msg_type == RADIUS_ACCT_INTERIM)
603 old->timeouts++;
604 }
605
606 next = old + 1;
607 if (next > &conf->acct_servers[conf->num_acct_servers - 1])
608 next = conf->acct_servers;
609 conf->acct_server = next;
610 radius_change_server(radius, next, old,
611 radius->acct_serv_sock,
612 radius->acct_serv_sock6, 0);
613 }
614
615
radius_client_update_timeout(struct radius_client_data * radius)616 static void radius_client_update_timeout(struct radius_client_data *radius)
617 {
618 struct os_reltime now;
619 os_time_t first;
620 struct radius_msg_list *entry;
621
622 eloop_cancel_timeout(radius_client_timer, radius, NULL);
623
624 if (radius->msgs == NULL) {
625 return;
626 }
627
628 first = 0;
629 for (entry = radius->msgs; entry; entry = entry->next) {
630 if (first == 0 || entry->next_try < first)
631 first = entry->next_try;
632 }
633
634 os_get_reltime(&now);
635 if (first < now.sec)
636 first = now.sec;
637 eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
638 NULL);
639 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
640 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
641 " %ld seconds", (long int) (first - now.sec));
642 }
643
644
radius_client_list_add(struct radius_client_data * radius,struct radius_msg * msg,RadiusType msg_type,const u8 * shared_secret,size_t shared_secret_len,const u8 * addr)645 static void radius_client_list_add(struct radius_client_data *radius,
646 struct radius_msg *msg,
647 RadiusType msg_type,
648 const u8 *shared_secret,
649 size_t shared_secret_len, const u8 *addr)
650 {
651 struct radius_msg_list *entry, *prev;
652
653 if (eloop_terminated()) {
654 /* No point in adding entries to retransmit queue since event
655 * loop has already been terminated. */
656 radius_msg_free(msg);
657 return;
658 }
659
660 entry = os_zalloc(sizeof(*entry));
661 if (entry == NULL) {
662 wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
663 radius_msg_free(msg);
664 return;
665 }
666
667 if (addr)
668 os_memcpy(entry->addr, addr, ETH_ALEN);
669 entry->msg = msg;
670 entry->msg_type = msg_type;
671 entry->shared_secret = shared_secret;
672 entry->shared_secret_len = shared_secret_len;
673 os_get_reltime(&entry->last_attempt);
674 entry->first_try = entry->last_attempt.sec;
675 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
676 entry->attempts = 1;
677 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
678 entry->next = radius->msgs;
679 radius->msgs = entry;
680 radius_client_update_timeout(radius);
681
682 if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
683 wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
684 prev = NULL;
685 while (entry->next) {
686 prev = entry;
687 entry = entry->next;
688 }
689 if (prev) {
690 prev->next = NULL;
691 radius_client_msg_free(entry);
692 }
693 } else
694 radius->num_msgs++;
695 }
696
697
698 /**
699 * radius_client_send - Send a RADIUS request
700 * @radius: RADIUS client context from radius_client_init()
701 * @msg: RADIUS message to be sent
702 * @msg_type: Message type (RADIUS_AUTH, RADIUS_ACCT, RADIUS_ACCT_INTERIM)
703 * @addr: MAC address of the device related to this message or %NULL
704 * Returns: 0 on success, -1 on failure
705 *
706 * This function is used to transmit a RADIUS authentication (RADIUS_AUTH) or
707 * accounting request (RADIUS_ACCT or RADIUS_ACCT_INTERIM). The only difference
708 * between accounting and interim accounting messages is that the interim
709 * message will not be retransmitted. Instead, a callback is used to indicate
710 * that the transmission failed for the specific station @addr so that a new
711 * interim accounting update message can be generated with up-to-date session
712 * data instead of trying to resend old information.
713 *
714 * The message is added on the retransmission queue and will be retransmitted
715 * automatically until a response is received or maximum number of retries
716 * (RADIUS_CLIENT_MAX_RETRIES) is reached. No such retries are used with
717 * RADIUS_ACCT_INTERIM, i.e., such a pending message is removed from the queue
718 * automatically on transmission failure.
719 *
720 * The related device MAC address can be used to identify pending messages that
721 * can be removed with radius_client_flush_auth().
722 */
radius_client_send(struct radius_client_data * radius,struct radius_msg * msg,RadiusType msg_type,const u8 * addr)723 int radius_client_send(struct radius_client_data *radius,
724 struct radius_msg *msg, RadiusType msg_type,
725 const u8 *addr)
726 {
727 struct hostapd_radius_servers *conf = radius->conf;
728 const u8 *shared_secret;
729 size_t shared_secret_len;
730 char *name;
731 int s, res;
732 struct wpabuf *buf;
733
734 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
735 if (conf->acct_server && radius->acct_sock < 0)
736 radius_client_init_acct(radius);
737
738 if (conf->acct_server == NULL || radius->acct_sock < 0 ||
739 conf->acct_server->shared_secret == NULL) {
740 hostapd_logger(radius->ctx, NULL,
741 HOSTAPD_MODULE_RADIUS,
742 HOSTAPD_LEVEL_INFO,
743 "No accounting server configured");
744 return -1;
745 }
746 shared_secret = conf->acct_server->shared_secret;
747 shared_secret_len = conf->acct_server->shared_secret_len;
748 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
749 name = "accounting";
750 s = radius->acct_sock;
751 conf->acct_server->requests++;
752 } else {
753 if (conf->auth_server && radius->auth_sock < 0)
754 radius_client_init_auth(radius);
755
756 if (conf->auth_server == NULL || radius->auth_sock < 0 ||
757 conf->auth_server->shared_secret == NULL) {
758 hostapd_logger(radius->ctx, NULL,
759 HOSTAPD_MODULE_RADIUS,
760 HOSTAPD_LEVEL_INFO,
761 "No authentication server configured");
762 return -1;
763 }
764 shared_secret = conf->auth_server->shared_secret;
765 shared_secret_len = conf->auth_server->shared_secret_len;
766 radius_msg_finish(msg, shared_secret, shared_secret_len);
767 name = "authentication";
768 s = radius->auth_sock;
769 conf->auth_server->requests++;
770 }
771
772 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
773 HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
774 "server", name);
775 if (conf->msg_dumps)
776 radius_msg_dump(msg);
777
778 buf = radius_msg_get_buf(msg);
779 res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
780 if (res < 0)
781 radius_client_handle_send_error(radius, s, msg_type);
782
783 radius_client_list_add(radius, msg, msg_type, shared_secret,
784 shared_secret_len, addr);
785
786 return 0;
787 }
788
789
radius_client_receive(int sock,void * eloop_ctx,void * sock_ctx)790 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
791 {
792 struct radius_client_data *radius = eloop_ctx;
793 struct hostapd_radius_servers *conf = radius->conf;
794 RadiusType msg_type = (RadiusType) sock_ctx;
795 int len, roundtrip;
796 unsigned char buf[3000];
797 struct radius_msg *msg;
798 struct radius_hdr *hdr;
799 struct radius_rx_handler *handlers;
800 size_t num_handlers, i;
801 struct radius_msg_list *req, *prev_req;
802 struct os_reltime now;
803 struct hostapd_radius_server *rconf;
804 int invalid_authenticator = 0;
805
806 if (msg_type == RADIUS_ACCT) {
807 handlers = radius->acct_handlers;
808 num_handlers = radius->num_acct_handlers;
809 rconf = conf->acct_server;
810 } else {
811 handlers = radius->auth_handlers;
812 num_handlers = radius->num_auth_handlers;
813 rconf = conf->auth_server;
814 }
815
816 len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
817 if (len < 0) {
818 wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
819 return;
820 }
821 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
822 HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
823 "server", len);
824 if (len == sizeof(buf)) {
825 wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
826 return;
827 }
828
829 msg = radius_msg_parse(buf, len);
830 if (msg == NULL) {
831 wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
832 rconf->malformed_responses++;
833 return;
834 }
835 hdr = radius_msg_get_hdr(msg);
836
837 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
838 HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
839 if (conf->msg_dumps)
840 radius_msg_dump(msg);
841
842 switch (hdr->code) {
843 case RADIUS_CODE_ACCESS_ACCEPT:
844 rconf->access_accepts++;
845 break;
846 case RADIUS_CODE_ACCESS_REJECT:
847 rconf->access_rejects++;
848 break;
849 case RADIUS_CODE_ACCESS_CHALLENGE:
850 rconf->access_challenges++;
851 break;
852 case RADIUS_CODE_ACCOUNTING_RESPONSE:
853 rconf->responses++;
854 break;
855 }
856
857 prev_req = NULL;
858 req = radius->msgs;
859 while (req) {
860 /* TODO: also match by src addr:port of the packet when using
861 * alternative RADIUS servers (?) */
862 if ((req->msg_type == msg_type ||
863 (req->msg_type == RADIUS_ACCT_INTERIM &&
864 msg_type == RADIUS_ACCT)) &&
865 radius_msg_get_hdr(req->msg)->identifier ==
866 hdr->identifier)
867 break;
868
869 prev_req = req;
870 req = req->next;
871 }
872
873 if (req == NULL) {
874 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
875 HOSTAPD_LEVEL_DEBUG,
876 "No matching RADIUS request found (type=%d "
877 "id=%d) - dropping packet",
878 msg_type, hdr->identifier);
879 goto fail;
880 }
881
882 os_get_reltime(&now);
883 roundtrip = (now.sec - req->last_attempt.sec) * 100 +
884 (now.usec - req->last_attempt.usec) / 10000;
885 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
886 HOSTAPD_LEVEL_DEBUG,
887 "Received RADIUS packet matched with a pending "
888 "request, round trip time %d.%02d sec",
889 roundtrip / 100, roundtrip % 100);
890 rconf->round_trip_time = roundtrip;
891
892 /* Remove ACKed RADIUS packet from retransmit list */
893 if (prev_req)
894 prev_req->next = req->next;
895 else
896 radius->msgs = req->next;
897 radius->num_msgs--;
898
899 for (i = 0; i < num_handlers; i++) {
900 RadiusRxResult res;
901 res = handlers[i].handler(msg, req->msg, req->shared_secret,
902 req->shared_secret_len,
903 handlers[i].data);
904 switch (res) {
905 case RADIUS_RX_PROCESSED:
906 radius_msg_free(msg);
907 /* continue */
908 case RADIUS_RX_QUEUED:
909 radius_client_msg_free(req);
910 return;
911 case RADIUS_RX_INVALID_AUTHENTICATOR:
912 invalid_authenticator++;
913 /* continue */
914 case RADIUS_RX_UNKNOWN:
915 /* continue with next handler */
916 break;
917 }
918 }
919
920 if (invalid_authenticator)
921 rconf->bad_authenticators++;
922 else
923 rconf->unknown_types++;
924 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
925 HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
926 "(type=%d code=%d id=%d)%s - dropping packet",
927 msg_type, hdr->code, hdr->identifier,
928 invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
929 "");
930 radius_client_msg_free(req);
931
932 fail:
933 radius_msg_free(msg);
934 }
935
936
937 /**
938 * radius_client_get_id - Get an identifier for a new RADIUS message
939 * @radius: RADIUS client context from radius_client_init()
940 * Returns: Allocated identifier
941 *
942 * This function is used to fetch a unique (among pending requests) identifier
943 * for a new RADIUS message.
944 */
radius_client_get_id(struct radius_client_data * radius)945 u8 radius_client_get_id(struct radius_client_data *radius)
946 {
947 struct radius_msg_list *entry, *prev, *_remove;
948 u8 id = radius->next_radius_identifier++;
949
950 /* remove entries with matching id from retransmit list to avoid
951 * using new reply from the RADIUS server with an old request */
952 entry = radius->msgs;
953 prev = NULL;
954 while (entry) {
955 if (radius_msg_get_hdr(entry->msg)->identifier == id) {
956 hostapd_logger(radius->ctx, entry->addr,
957 HOSTAPD_MODULE_RADIUS,
958 HOSTAPD_LEVEL_DEBUG,
959 "Removing pending RADIUS message, "
960 "since its id (%d) is reused", id);
961 if (prev)
962 prev->next = entry->next;
963 else
964 radius->msgs = entry->next;
965 _remove = entry;
966 } else {
967 _remove = NULL;
968 prev = entry;
969 }
970 entry = entry->next;
971
972 if (_remove)
973 radius_client_msg_free(_remove);
974 }
975
976 return id;
977 }
978
979
980 /**
981 * radius_client_flush - Flush all pending RADIUS client messages
982 * @radius: RADIUS client context from radius_client_init()
983 * @only_auth: Whether only authentication messages are removed
984 */
radius_client_flush(struct radius_client_data * radius,int only_auth)985 void radius_client_flush(struct radius_client_data *radius, int only_auth)
986 {
987 struct radius_msg_list *entry, *prev, *tmp;
988
989 if (!radius)
990 return;
991
992 prev = NULL;
993 entry = radius->msgs;
994
995 while (entry) {
996 if (!only_auth || entry->msg_type == RADIUS_AUTH) {
997 if (prev)
998 prev->next = entry->next;
999 else
1000 radius->msgs = entry->next;
1001
1002 tmp = entry;
1003 entry = entry->next;
1004 radius_client_msg_free(tmp);
1005 radius->num_msgs--;
1006 } else {
1007 prev = entry;
1008 entry = entry->next;
1009 }
1010 }
1011
1012 if (radius->msgs == NULL)
1013 eloop_cancel_timeout(radius_client_timer, radius, NULL);
1014 }
1015
1016
radius_client_update_acct_msgs(struct radius_client_data * radius,const u8 * shared_secret,size_t shared_secret_len)1017 static void radius_client_update_acct_msgs(struct radius_client_data *radius,
1018 const u8 *shared_secret,
1019 size_t shared_secret_len)
1020 {
1021 struct radius_msg_list *entry;
1022
1023 if (!radius)
1024 return;
1025
1026 for (entry = radius->msgs; entry; entry = entry->next) {
1027 if (entry->msg_type == RADIUS_ACCT) {
1028 entry->shared_secret = shared_secret;
1029 entry->shared_secret_len = shared_secret_len;
1030 radius_msg_finish_acct(entry->msg, shared_secret,
1031 shared_secret_len);
1032 }
1033 }
1034 }
1035
1036
1037 static int
radius_change_server(struct radius_client_data * radius,struct hostapd_radius_server * nserv,struct hostapd_radius_server * oserv,int sock,int sock6,int auth)1038 radius_change_server(struct radius_client_data *radius,
1039 struct hostapd_radius_server *nserv,
1040 struct hostapd_radius_server *oserv,
1041 int sock, int sock6, int auth)
1042 {
1043 struct sockaddr_in serv, claddr;
1044 #ifdef CONFIG_IPV6
1045 struct sockaddr_in6 serv6, claddr6;
1046 #endif /* CONFIG_IPV6 */
1047 struct sockaddr *addr, *cl_addr;
1048 socklen_t addrlen, claddrlen;
1049 char abuf[50];
1050 int sel_sock;
1051 struct radius_msg_list *entry;
1052 struct hostapd_radius_servers *conf = radius->conf;
1053 struct sockaddr_in disconnect_addr = {
1054 .sin_family = AF_UNSPEC,
1055 };
1056
1057 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
1058 HOSTAPD_LEVEL_INFO,
1059 "%s server %s:%d",
1060 auth ? "Authentication" : "Accounting",
1061 hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
1062 nserv->port);
1063
1064 if (oserv && oserv == nserv) {
1065 /* Reconnect to same server, flush */
1066 if (auth)
1067 radius_client_flush(radius, 1);
1068 }
1069
1070 if (oserv && oserv != nserv &&
1071 (nserv->shared_secret_len != oserv->shared_secret_len ||
1072 os_memcmp(nserv->shared_secret, oserv->shared_secret,
1073 nserv->shared_secret_len) != 0)) {
1074 /* Pending RADIUS packets used different shared secret, so
1075 * they need to be modified. Update accounting message
1076 * authenticators here. Authentication messages are removed
1077 * since they would require more changes and the new RADIUS
1078 * server may not be prepared to receive them anyway due to
1079 * missing state information. Client will likely retry
1080 * authentication, so this should not be an issue. */
1081 if (auth)
1082 radius_client_flush(radius, 1);
1083 else {
1084 radius_client_update_acct_msgs(
1085 radius, nserv->shared_secret,
1086 nserv->shared_secret_len);
1087 }
1088 }
1089
1090 /* Reset retry counters for the new server */
1091 for (entry = radius->msgs; oserv && oserv != nserv && entry;
1092 entry = entry->next) {
1093 if ((auth && entry->msg_type != RADIUS_AUTH) ||
1094 (!auth && entry->msg_type != RADIUS_ACCT))
1095 continue;
1096 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
1097 entry->attempts = 0;
1098 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
1099 }
1100
1101 if (radius->msgs) {
1102 eloop_cancel_timeout(radius_client_timer, radius, NULL);
1103 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
1104 radius_client_timer, radius, NULL);
1105 }
1106
1107 switch (nserv->addr.af) {
1108 case AF_INET:
1109 os_memset(&serv, 0, sizeof(serv));
1110 serv.sin_family = AF_INET;
1111 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
1112 serv.sin_port = htons(nserv->port);
1113 addr = (struct sockaddr *) &serv;
1114 addrlen = sizeof(serv);
1115 sel_sock = sock;
1116 break;
1117 #ifdef CONFIG_IPV6
1118 case AF_INET6:
1119 os_memset(&serv6, 0, sizeof(serv6));
1120 serv6.sin6_family = AF_INET6;
1121 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
1122 sizeof(struct in6_addr));
1123 serv6.sin6_port = htons(nserv->port);
1124 addr = (struct sockaddr *) &serv6;
1125 addrlen = sizeof(serv6);
1126 sel_sock = sock6;
1127 break;
1128 #endif /* CONFIG_IPV6 */
1129 default:
1130 return -1;
1131 }
1132
1133 if (sel_sock < 0) {
1134 wpa_printf(MSG_INFO,
1135 "RADIUS: No server socket available (af=%d sock=%d sock6=%d auth=%d",
1136 nserv->addr.af, sock, sock6, auth);
1137 return -1;
1138 }
1139
1140 if (conf->force_client_addr) {
1141 switch (conf->client_addr.af) {
1142 case AF_INET:
1143 os_memset(&claddr, 0, sizeof(claddr));
1144 claddr.sin_family = AF_INET;
1145 claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
1146 claddr.sin_port = htons(0);
1147 cl_addr = (struct sockaddr *) &claddr;
1148 claddrlen = sizeof(claddr);
1149 break;
1150 #ifdef CONFIG_IPV6
1151 case AF_INET6:
1152 os_memset(&claddr6, 0, sizeof(claddr6));
1153 claddr6.sin6_family = AF_INET6;
1154 os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
1155 sizeof(struct in6_addr));
1156 claddr6.sin6_port = htons(0);
1157 cl_addr = (struct sockaddr *) &claddr6;
1158 claddrlen = sizeof(claddr6);
1159 break;
1160 #endif /* CONFIG_IPV6 */
1161 default:
1162 return -1;
1163 }
1164
1165 if (bind(sel_sock, cl_addr, claddrlen) < 0) {
1166 wpa_printf(MSG_INFO, "bind[radius]: %s",
1167 strerror(errno));
1168 return -1;
1169 }
1170 }
1171
1172 /* Force a reconnect by disconnecting the socket first */
1173 if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
1174 sizeof(disconnect_addr)) < 0)
1175 wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
1176
1177 if (connect(sel_sock, addr, addrlen) < 0) {
1178 wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
1179 return -1;
1180 }
1181
1182 #ifndef CONFIG_NATIVE_WINDOWS
1183 switch (nserv->addr.af) {
1184 case AF_INET:
1185 claddrlen = sizeof(claddr);
1186 if (getsockname(sel_sock, (struct sockaddr *) &claddr,
1187 &claddrlen) == 0) {
1188 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1189 inet_ntoa(claddr.sin_addr),
1190 ntohs(claddr.sin_port));
1191 }
1192 break;
1193 #ifdef CONFIG_IPV6
1194 case AF_INET6: {
1195 claddrlen = sizeof(claddr6);
1196 if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
1197 &claddrlen) == 0) {
1198 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1199 inet_ntop(AF_INET6, &claddr6.sin6_addr,
1200 abuf, sizeof(abuf)),
1201 ntohs(claddr6.sin6_port));
1202 }
1203 break;
1204 }
1205 #endif /* CONFIG_IPV6 */
1206 }
1207 #endif /* CONFIG_NATIVE_WINDOWS */
1208
1209 if (auth)
1210 radius->auth_sock = sel_sock;
1211 else
1212 radius->acct_sock = sel_sock;
1213
1214 return 0;
1215 }
1216
1217
radius_retry_primary_timer(void * eloop_ctx,void * timeout_ctx)1218 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
1219 {
1220 struct radius_client_data *radius = eloop_ctx;
1221 struct hostapd_radius_servers *conf = radius->conf;
1222 struct hostapd_radius_server *oserv;
1223
1224 if (radius->auth_sock >= 0 && conf->auth_servers &&
1225 conf->auth_server != conf->auth_servers) {
1226 oserv = conf->auth_server;
1227 conf->auth_server = conf->auth_servers;
1228 if (radius_change_server(radius, conf->auth_server, oserv,
1229 radius->auth_serv_sock,
1230 radius->auth_serv_sock6, 1) < 0) {
1231 conf->auth_server = oserv;
1232 radius_change_server(radius, oserv, conf->auth_server,
1233 radius->auth_serv_sock,
1234 radius->auth_serv_sock6, 1);
1235 }
1236 }
1237
1238 if (radius->acct_sock >= 0 && conf->acct_servers &&
1239 conf->acct_server != conf->acct_servers) {
1240 oserv = conf->acct_server;
1241 conf->acct_server = conf->acct_servers;
1242 if (radius_change_server(radius, conf->acct_server, oserv,
1243 radius->acct_serv_sock,
1244 radius->acct_serv_sock6, 0) < 0) {
1245 conf->acct_server = oserv;
1246 radius_change_server(radius, oserv, conf->acct_server,
1247 radius->acct_serv_sock,
1248 radius->acct_serv_sock6, 0);
1249 }
1250 }
1251
1252 if (conf->retry_primary_interval)
1253 eloop_register_timeout(conf->retry_primary_interval, 0,
1254 radius_retry_primary_timer, radius,
1255 NULL);
1256 }
1257
1258
radius_client_disable_pmtu_discovery(int s)1259 static int radius_client_disable_pmtu_discovery(int s)
1260 {
1261 int r = -1;
1262 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1263 /* Turn off Path MTU discovery on IPv4/UDP sockets. */
1264 int action = IP_PMTUDISC_DONT;
1265 r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
1266 sizeof(action));
1267 if (r == -1)
1268 wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
1269 strerror(errno));
1270 #endif
1271 return r;
1272 }
1273
1274
radius_close_auth_sockets(struct radius_client_data * radius)1275 static void radius_close_auth_sockets(struct radius_client_data *radius)
1276 {
1277 radius->auth_sock = -1;
1278
1279 if (radius->auth_serv_sock >= 0) {
1280 eloop_unregister_read_sock(radius->auth_serv_sock);
1281 close(radius->auth_serv_sock);
1282 radius->auth_serv_sock = -1;
1283 }
1284 #ifdef CONFIG_IPV6
1285 if (radius->auth_serv_sock6 >= 0) {
1286 eloop_unregister_read_sock(radius->auth_serv_sock6);
1287 close(radius->auth_serv_sock6);
1288 radius->auth_serv_sock6 = -1;
1289 }
1290 #endif /* CONFIG_IPV6 */
1291 }
1292
1293
radius_close_acct_sockets(struct radius_client_data * radius)1294 static void radius_close_acct_sockets(struct radius_client_data *radius)
1295 {
1296 radius->acct_sock = -1;
1297
1298 if (radius->acct_serv_sock >= 0) {
1299 eloop_unregister_read_sock(radius->acct_serv_sock);
1300 close(radius->acct_serv_sock);
1301 radius->acct_serv_sock = -1;
1302 }
1303 #ifdef CONFIG_IPV6
1304 if (radius->acct_serv_sock6 >= 0) {
1305 eloop_unregister_read_sock(radius->acct_serv_sock6);
1306 close(radius->acct_serv_sock6);
1307 radius->acct_serv_sock6 = -1;
1308 }
1309 #endif /* CONFIG_IPV6 */
1310 }
1311
1312
radius_client_init_auth(struct radius_client_data * radius)1313 static int radius_client_init_auth(struct radius_client_data *radius)
1314 {
1315 struct hostapd_radius_servers *conf = radius->conf;
1316 int ok = 0;
1317
1318 radius_close_auth_sockets(radius);
1319
1320 radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1321 if (radius->auth_serv_sock < 0)
1322 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1323 strerror(errno));
1324 else {
1325 radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
1326 ok++;
1327 }
1328
1329 #ifdef CONFIG_IPV6
1330 radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1331 if (radius->auth_serv_sock6 < 0)
1332 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1333 strerror(errno));
1334 else
1335 ok++;
1336 #endif /* CONFIG_IPV6 */
1337
1338 if (ok == 0)
1339 return -1;
1340
1341 radius_change_server(radius, conf->auth_server, NULL,
1342 radius->auth_serv_sock, radius->auth_serv_sock6,
1343 1);
1344
1345 if (radius->auth_serv_sock >= 0 &&
1346 eloop_register_read_sock(radius->auth_serv_sock,
1347 radius_client_receive, radius,
1348 (void *) RADIUS_AUTH)) {
1349 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1350 radius_close_auth_sockets(radius);
1351 return -1;
1352 }
1353
1354 #ifdef CONFIG_IPV6
1355 if (radius->auth_serv_sock6 >= 0 &&
1356 eloop_register_read_sock(radius->auth_serv_sock6,
1357 radius_client_receive, radius,
1358 (void *) RADIUS_AUTH)) {
1359 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1360 radius_close_auth_sockets(radius);
1361 return -1;
1362 }
1363 #endif /* CONFIG_IPV6 */
1364
1365 return 0;
1366 }
1367
1368
radius_client_init_acct(struct radius_client_data * radius)1369 static int radius_client_init_acct(struct radius_client_data *radius)
1370 {
1371 struct hostapd_radius_servers *conf = radius->conf;
1372 int ok = 0;
1373
1374 radius_close_acct_sockets(radius);
1375
1376 radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1377 if (radius->acct_serv_sock < 0)
1378 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1379 strerror(errno));
1380 else {
1381 radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
1382 ok++;
1383 }
1384
1385 #ifdef CONFIG_IPV6
1386 radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1387 if (radius->acct_serv_sock6 < 0)
1388 wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1389 strerror(errno));
1390 else
1391 ok++;
1392 #endif /* CONFIG_IPV6 */
1393
1394 if (ok == 0)
1395 return -1;
1396
1397 radius_change_server(radius, conf->acct_server, NULL,
1398 radius->acct_serv_sock, radius->acct_serv_sock6,
1399 0);
1400
1401 if (radius->acct_serv_sock >= 0 &&
1402 eloop_register_read_sock(radius->acct_serv_sock,
1403 radius_client_receive, radius,
1404 (void *) RADIUS_ACCT)) {
1405 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1406 radius_close_acct_sockets(radius);
1407 return -1;
1408 }
1409
1410 #ifdef CONFIG_IPV6
1411 if (radius->acct_serv_sock6 >= 0 &&
1412 eloop_register_read_sock(radius->acct_serv_sock6,
1413 radius_client_receive, radius,
1414 (void *) RADIUS_ACCT)) {
1415 wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1416 radius_close_acct_sockets(radius);
1417 return -1;
1418 }
1419 #endif /* CONFIG_IPV6 */
1420
1421 return 0;
1422 }
1423
1424
1425 /**
1426 * radius_client_init - Initialize RADIUS client
1427 * @ctx: Callback context to be used in hostapd_logger() calls
1428 * @conf: RADIUS client configuration (RADIUS servers)
1429 * Returns: Pointer to private RADIUS client context or %NULL on failure
1430 *
1431 * The caller is responsible for keeping the configuration data available for
1432 * the lifetime of the RADIUS client, i.e., until radius_client_deinit() is
1433 * called for the returned context pointer.
1434 */
1435 struct radius_client_data *
radius_client_init(void * ctx,struct hostapd_radius_servers * conf)1436 radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
1437 {
1438 struct radius_client_data *radius;
1439
1440 radius = os_zalloc(sizeof(struct radius_client_data));
1441 if (radius == NULL)
1442 return NULL;
1443
1444 radius->ctx = ctx;
1445 radius->conf = conf;
1446 radius->auth_serv_sock = radius->acct_serv_sock =
1447 radius->auth_serv_sock6 = radius->acct_serv_sock6 =
1448 radius->auth_sock = radius->acct_sock = -1;
1449
1450 if (conf->auth_server && radius_client_init_auth(radius)) {
1451 radius_client_deinit(radius);
1452 return NULL;
1453 }
1454
1455 if (conf->acct_server && radius_client_init_acct(radius)) {
1456 radius_client_deinit(radius);
1457 return NULL;
1458 }
1459
1460 if (conf->retry_primary_interval)
1461 eloop_register_timeout(conf->retry_primary_interval, 0,
1462 radius_retry_primary_timer, radius,
1463 NULL);
1464
1465 return radius;
1466 }
1467
1468
1469 /**
1470 * radius_client_deinit - Deinitialize RADIUS client
1471 * @radius: RADIUS client context from radius_client_init()
1472 */
radius_client_deinit(struct radius_client_data * radius)1473 void radius_client_deinit(struct radius_client_data *radius)
1474 {
1475 if (!radius)
1476 return;
1477
1478 radius_close_auth_sockets(radius);
1479 radius_close_acct_sockets(radius);
1480
1481 eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
1482
1483 radius_client_flush(radius, 0);
1484 os_free(radius->auth_handlers);
1485 os_free(radius->acct_handlers);
1486 os_free(radius);
1487 }
1488
1489
1490 /**
1491 * radius_client_flush_auth - Flush pending RADIUS messages for an address
1492 * @radius: RADIUS client context from radius_client_init()
1493 * @addr: MAC address of the related device
1494 *
1495 * This function can be used to remove pending RADIUS authentication messages
1496 * that are related to a specific device. The addr parameter is matched with
1497 * the one used in radius_client_send() call that was used to transmit the
1498 * authentication request.
1499 */
radius_client_flush_auth(struct radius_client_data * radius,const u8 * addr)1500 void radius_client_flush_auth(struct radius_client_data *radius,
1501 const u8 *addr)
1502 {
1503 struct radius_msg_list *entry, *prev, *tmp;
1504
1505 prev = NULL;
1506 entry = radius->msgs;
1507 while (entry) {
1508 if (entry->msg_type == RADIUS_AUTH &&
1509 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1510 hostapd_logger(radius->ctx, addr,
1511 HOSTAPD_MODULE_RADIUS,
1512 HOSTAPD_LEVEL_DEBUG,
1513 "Removing pending RADIUS authentication"
1514 " message for removed client");
1515
1516 if (prev)
1517 prev->next = entry->next;
1518 else
1519 radius->msgs = entry->next;
1520
1521 tmp = entry;
1522 entry = entry->next;
1523 radius_client_msg_free(tmp);
1524 radius->num_msgs--;
1525 continue;
1526 }
1527
1528 prev = entry;
1529 entry = entry->next;
1530 }
1531 }
1532
1533
radius_client_dump_auth_server(char * buf,size_t buflen,struct hostapd_radius_server * serv,struct radius_client_data * cli)1534 static int radius_client_dump_auth_server(char *buf, size_t buflen,
1535 struct hostapd_radius_server *serv,
1536 struct radius_client_data *cli)
1537 {
1538 int pending = 0;
1539 struct radius_msg_list *msg;
1540 char abuf[50];
1541
1542 if (cli) {
1543 for (msg = cli->msgs; msg; msg = msg->next) {
1544 if (msg->msg_type == RADIUS_AUTH)
1545 pending++;
1546 }
1547 }
1548
1549 return os_snprintf(buf, buflen,
1550 "radiusAuthServerIndex=%d\n"
1551 "radiusAuthServerAddress=%s\n"
1552 "radiusAuthClientServerPortNumber=%d\n"
1553 "radiusAuthClientRoundTripTime=%d\n"
1554 "radiusAuthClientAccessRequests=%u\n"
1555 "radiusAuthClientAccessRetransmissions=%u\n"
1556 "radiusAuthClientAccessAccepts=%u\n"
1557 "radiusAuthClientAccessRejects=%u\n"
1558 "radiusAuthClientAccessChallenges=%u\n"
1559 "radiusAuthClientMalformedAccessResponses=%u\n"
1560 "radiusAuthClientBadAuthenticators=%u\n"
1561 "radiusAuthClientPendingRequests=%u\n"
1562 "radiusAuthClientTimeouts=%u\n"
1563 "radiusAuthClientUnknownTypes=%u\n"
1564 "radiusAuthClientPacketsDropped=%u\n",
1565 serv->index,
1566 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1567 serv->port,
1568 serv->round_trip_time,
1569 serv->requests,
1570 serv->retransmissions,
1571 serv->access_accepts,
1572 serv->access_rejects,
1573 serv->access_challenges,
1574 serv->malformed_responses,
1575 serv->bad_authenticators,
1576 pending,
1577 serv->timeouts,
1578 serv->unknown_types,
1579 serv->packets_dropped);
1580 }
1581
1582
radius_client_dump_acct_server(char * buf,size_t buflen,struct hostapd_radius_server * serv,struct radius_client_data * cli)1583 static int radius_client_dump_acct_server(char *buf, size_t buflen,
1584 struct hostapd_radius_server *serv,
1585 struct radius_client_data *cli)
1586 {
1587 int pending = 0;
1588 struct radius_msg_list *msg;
1589 char abuf[50];
1590
1591 if (cli) {
1592 for (msg = cli->msgs; msg; msg = msg->next) {
1593 if (msg->msg_type == RADIUS_ACCT ||
1594 msg->msg_type == RADIUS_ACCT_INTERIM)
1595 pending++;
1596 }
1597 }
1598
1599 return os_snprintf(buf, buflen,
1600 "radiusAccServerIndex=%d\n"
1601 "radiusAccServerAddress=%s\n"
1602 "radiusAccClientServerPortNumber=%d\n"
1603 "radiusAccClientRoundTripTime=%d\n"
1604 "radiusAccClientRequests=%u\n"
1605 "radiusAccClientRetransmissions=%u\n"
1606 "radiusAccClientResponses=%u\n"
1607 "radiusAccClientMalformedResponses=%u\n"
1608 "radiusAccClientBadAuthenticators=%u\n"
1609 "radiusAccClientPendingRequests=%u\n"
1610 "radiusAccClientTimeouts=%u\n"
1611 "radiusAccClientUnknownTypes=%u\n"
1612 "radiusAccClientPacketsDropped=%u\n",
1613 serv->index,
1614 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
1615 serv->port,
1616 serv->round_trip_time,
1617 serv->requests,
1618 serv->retransmissions,
1619 serv->responses,
1620 serv->malformed_responses,
1621 serv->bad_authenticators,
1622 pending,
1623 serv->timeouts,
1624 serv->unknown_types,
1625 serv->packets_dropped);
1626 }
1627
1628
1629 /**
1630 * radius_client_get_mib - Get RADIUS client MIB information
1631 * @radius: RADIUS client context from radius_client_init()
1632 * @buf: Buffer for returning MIB data in text format
1633 * @buflen: Maximum buf length in octets
1634 * Returns: Number of octets written into the buffer
1635 */
radius_client_get_mib(struct radius_client_data * radius,char * buf,size_t buflen)1636 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1637 size_t buflen)
1638 {
1639 struct hostapd_radius_servers *conf = radius->conf;
1640 int i;
1641 struct hostapd_radius_server *serv;
1642 int count = 0;
1643
1644 if (conf->auth_servers) {
1645 for (i = 0; i < conf->num_auth_servers; i++) {
1646 serv = &conf->auth_servers[i];
1647 count += radius_client_dump_auth_server(
1648 buf + count, buflen - count, serv,
1649 serv == conf->auth_server ?
1650 radius : NULL);
1651 }
1652 }
1653
1654 if (conf->acct_servers) {
1655 for (i = 0; i < conf->num_acct_servers; i++) {
1656 serv = &conf->acct_servers[i];
1657 count += radius_client_dump_acct_server(
1658 buf + count, buflen - count, serv,
1659 serv == conf->acct_server ?
1660 radius : NULL);
1661 }
1662 }
1663
1664 return count;
1665 }
1666
1667
radius_client_reconfig(struct radius_client_data * radius,struct hostapd_radius_servers * conf)1668 void radius_client_reconfig(struct radius_client_data *radius,
1669 struct hostapd_radius_servers *conf)
1670 {
1671 if (radius)
1672 radius->conf = conf;
1673 }
1674