Line data Source code
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 :
253 7862 : static void radius_client_msg_free(struct radius_msg_list *req)
254 : {
255 7862 : radius_msg_free(req->msg);
256 7862 : os_free(req);
257 7862 : }
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 : */
276 6120 : 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 6120 : if (msg_type == RADIUS_ACCT) {
289 2039 : handlers = &radius->acct_handlers;
290 2039 : num = &radius->num_acct_handlers;
291 : } else {
292 4081 : handlers = &radius->auth_handlers;
293 4081 : num = &radius->num_auth_handlers;
294 : }
295 :
296 6120 : newh = os_realloc_array(*handlers, *num + 1,
297 : sizeof(struct radius_rx_handler));
298 6120 : if (newh == NULL)
299 1 : return -1;
300 :
301 6119 : newh[*num].handler = handler;
302 6119 : newh[*num].data = data;
303 6119 : (*num)++;
304 6119 : *handlers = newh;
305 :
306 6119 : 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 : */
320 2038 : 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 2038 : radius->interim_error_cb = cb;
325 2038 : radius->interim_error_cb_ctx = ctx;
326 2038 : }
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 : */
333 8 : 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 8 : int _errno = errno;
338 8 : wpa_printf(MSG_INFO, "send[RADIUS,s=%d]: %s", s, strerror(errno));
339 8 : if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
340 8 : _errno == EBADF || _errno == ENETUNREACH || _errno == EACCES) {
341 4 : 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 4 : if (msg_type == RADIUS_ACCT ||
346 : msg_type == RADIUS_ACCT_INTERIM) {
347 2 : radius_client_init_acct(radius);
348 2 : return 0;
349 : } else {
350 2 : radius_client_init_auth(radius);
351 2 : return 1;
352 : }
353 : }
354 : #endif /* CONFIG_NATIVE_WINDOWS */
355 :
356 4 : return 0;
357 : }
358 :
359 :
360 37 : static int radius_client_retransmit(struct radius_client_data *radius,
361 : struct radius_msg_list *entry,
362 : os_time_t now)
363 : {
364 37 : 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 58 : if (entry->msg_type == RADIUS_ACCT ||
372 21 : entry->msg_type == RADIUS_ACCT_INTERIM) {
373 18 : if (radius->acct_sock < 0)
374 2 : radius_client_init_acct(radius);
375 18 : if (radius->acct_sock < 0 && conf->num_acct_servers > 1) {
376 0 : prev_num_msgs = radius->num_msgs;
377 0 : radius_client_acct_failover(radius);
378 0 : if (prev_num_msgs != radius->num_msgs)
379 0 : return 0;
380 : }
381 18 : s = radius->acct_sock;
382 36 : if (entry->attempts == 0)
383 1 : conf->acct_server->requests++;
384 : else {
385 17 : conf->acct_server->timeouts++;
386 17 : conf->acct_server->retransmissions++;
387 : }
388 : } else {
389 19 : if (radius->auth_sock < 0)
390 1 : radius_client_init_auth(radius);
391 19 : if (radius->auth_sock < 0 && conf->num_auth_servers > 1) {
392 0 : prev_num_msgs = radius->num_msgs;
393 0 : radius_client_auth_failover(radius);
394 0 : if (prev_num_msgs != radius->num_msgs)
395 0 : return 0;
396 : }
397 19 : s = radius->auth_sock;
398 19 : if (entry->attempts == 0)
399 0 : conf->auth_server->requests++;
400 : else {
401 19 : conf->auth_server->timeouts++;
402 19 : conf->auth_server->retransmissions++;
403 : }
404 : }
405 :
406 37 : if (entry->msg_type == RADIUS_ACCT_INTERIM) {
407 12 : wpa_printf(MSG_DEBUG,
408 : "RADIUS: Failed to transmit interim accounting update to "
409 : MACSTR " - drop message and request a new update",
410 12 : MAC2STR(entry->addr));
411 2 : if (radius->interim_error_cb)
412 2 : radius->interim_error_cb(entry->addr,
413 : radius->interim_error_cb_ctx);
414 2 : return 1;
415 : }
416 :
417 35 : if (s < 0) {
418 3 : wpa_printf(MSG_INFO,
419 : "RADIUS: No valid socket for retransmission");
420 3 : return 1;
421 : }
422 :
423 46 : if (entry->msg_type == RADIUS_ACCT &&
424 14 : radius_msg_get_attr_ptr(entry->msg, RADIUS_ATTR_ACCT_DELAY_TIME,
425 : &acct_delay_time, &acct_delay_time_len,
426 14 : NULL) == 0 &&
427 14 : 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 14 : hdr = radius_msg_get_hdr(entry->msg);
436 14 : hdr->identifier = radius_client_get_id(radius);
437 :
438 : /* Update Acct-Delay-Time to show wait time in queue */
439 14 : delay_time = now - entry->first_try;
440 14 : WPA_PUT_BE32(acct_delay_time, delay_time);
441 :
442 14 : wpa_printf(MSG_DEBUG,
443 : "RADIUS: Updated Acct-Delay-Time to %u for retransmission",
444 : delay_time);
445 14 : radius_msg_finish_acct(entry->msg, entry->shared_secret,
446 : entry->shared_secret_len);
447 14 : if (radius->conf->msg_dumps)
448 14 : radius_msg_dump(entry->msg);
449 : }
450 :
451 : /* retransmit; remove entry if too many attempts */
452 32 : entry->attempts++;
453 32 : hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
454 : HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
455 32 : radius_msg_get_hdr(entry->msg)->identifier);
456 :
457 32 : os_get_reltime(&entry->last_attempt);
458 32 : buf = radius_msg_get_buf(entry->msg);
459 32 : if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) {
460 5 : if (radius_client_handle_send_error(radius, s, entry->msg_type)
461 : > 0)
462 0 : return 0;
463 : }
464 :
465 32 : entry->next_try = now + entry->next_wait;
466 32 : entry->next_wait *= 2;
467 32 : if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
468 0 : entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
469 32 : if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
470 0 : wpa_printf(MSG_INFO, "RADIUS: Removing un-ACKed message due to too many failed retransmit attempts");
471 0 : return 1;
472 : }
473 :
474 32 : return 0;
475 : }
476 :
477 :
478 74 : static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
479 : {
480 74 : 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 74 : int auth_failover = 0, acct_failover = 0;
485 : size_t prev_num_msgs;
486 : int s;
487 :
488 74 : entry = radius->msgs;
489 74 : if (!entry)
490 119 : return;
491 :
492 29 : os_get_reltime(&now);
493 29 : first = 0;
494 :
495 29 : prev = NULL;
496 133 : while (entry) {
497 75 : prev_num_msgs = radius->num_msgs;
498 112 : if (now.sec >= entry->next_try &&
499 37 : radius_client_retransmit(radius, entry, now.sec)) {
500 5 : if (prev)
501 1 : prev->next = entry->next;
502 : else
503 4 : radius->msgs = entry->next;
504 :
505 5 : tmp = entry;
506 5 : entry = entry->next;
507 5 : radius_client_msg_free(tmp);
508 5 : radius->num_msgs--;
509 5 : continue;
510 : }
511 :
512 70 : if (prev_num_msgs != radius->num_msgs) {
513 0 : wpa_printf(MSG_DEBUG,
514 : "RADIUS: Message removed from queue - restart from beginning");
515 0 : entry = radius->msgs;
516 0 : prev = NULL;
517 0 : continue;
518 : }
519 :
520 70 : s = entry->msg_type == RADIUS_AUTH ? radius->auth_sock :
521 : radius->acct_sock;
522 70 : if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER ||
523 2 : (s < 0 && entry->attempts > 0)) {
524 3 : if (entry->msg_type == RADIUS_ACCT ||
525 1 : entry->msg_type == RADIUS_ACCT_INTERIM)
526 1 : acct_failover++;
527 : else
528 1 : auth_failover++;
529 : }
530 :
531 70 : if (first == 0 || entry->next_try < first)
532 32 : first = entry->next_try;
533 :
534 70 : prev = entry;
535 70 : entry = entry->next;
536 : }
537 :
538 29 : if (radius->msgs) {
539 27 : if (first < now.sec)
540 0 : first = now.sec;
541 27 : eloop_register_timeout(first - now.sec, 0,
542 : radius_client_timer, radius, NULL);
543 27 : hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
544 : HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
545 : "retransmit in %ld seconds",
546 27 : (long int) (first - now.sec));
547 : }
548 :
549 29 : if (auth_failover)
550 1 : radius_client_auth_failover(radius);
551 :
552 29 : if (acct_failover)
553 1 : radius_client_acct_failover(radius);
554 : }
555 :
556 :
557 1 : static void radius_client_auth_failover(struct radius_client_data *radius)
558 : {
559 1 : 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 1 : old = conf->auth_server;
565 2 : hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
566 : HOSTAPD_LEVEL_NOTICE,
567 : "No response from Authentication server %s:%d - failover",
568 1 : hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
569 : old->port);
570 :
571 3 : for (entry = radius->msgs; entry; entry = entry->next) {
572 2 : if (entry->msg_type == RADIUS_AUTH)
573 1 : old->timeouts++;
574 : }
575 :
576 1 : next = old + 1;
577 1 : if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
578 0 : next = conf->auth_servers;
579 1 : conf->auth_server = next;
580 1 : radius_change_server(radius, next, old,
581 : radius->auth_serv_sock,
582 : radius->auth_serv_sock6, 1);
583 1 : }
584 :
585 :
586 1 : static void radius_client_acct_failover(struct radius_client_data *radius)
587 : {
588 1 : 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 1 : old = conf->acct_server;
594 2 : hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
595 : HOSTAPD_LEVEL_NOTICE,
596 : "No response from Accounting server %s:%d - failover",
597 1 : hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
598 : old->port);
599 :
600 2 : for (entry = radius->msgs; entry; entry = entry->next) {
601 1 : if (entry->msg_type == RADIUS_ACCT ||
602 0 : entry->msg_type == RADIUS_ACCT_INTERIM)
603 1 : old->timeouts++;
604 : }
605 :
606 1 : next = old + 1;
607 1 : if (next > &conf->acct_servers[conf->num_acct_servers - 1])
608 0 : next = conf->acct_servers;
609 1 : conf->acct_server = next;
610 1 : radius_change_server(radius, next, old,
611 : radius->acct_serv_sock,
612 : radius->acct_serv_sock6, 0);
613 1 : }
614 :
615 :
616 7862 : 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 7862 : eloop_cancel_timeout(radius_client_timer, radius, NULL);
623 :
624 7862 : if (radius->msgs == NULL) {
625 7862 : return;
626 : }
627 :
628 7862 : first = 0;
629 19386 : for (entry = radius->msgs; entry; entry = entry->next) {
630 11524 : if (first == 0 || entry->next_try < first)
631 8117 : first = entry->next_try;
632 : }
633 :
634 7862 : os_get_reltime(&now);
635 7862 : if (first < now.sec)
636 0 : first = now.sec;
637 7862 : eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
638 : NULL);
639 7862 : hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
640 : HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
641 7862 : " %ld seconds", (long int) (first - now.sec));
642 : }
643 :
644 :
645 7867 : 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 7867 : if (eloop_terminated()) {
654 : /* No point in adding entries to retransmit queue since event
655 : * loop has already been terminated. */
656 0 : radius_msg_free(msg);
657 0 : return;
658 : }
659 :
660 7867 : entry = os_zalloc(sizeof(*entry));
661 7867 : if (entry == NULL) {
662 5 : wpa_printf(MSG_INFO, "RADIUS: Failed to add packet into retransmit list");
663 5 : radius_msg_free(msg);
664 5 : return;
665 : }
666 :
667 7862 : if (addr)
668 7745 : os_memcpy(entry->addr, addr, ETH_ALEN);
669 7862 : entry->msg = msg;
670 7862 : entry->msg_type = msg_type;
671 7862 : entry->shared_secret = shared_secret;
672 7862 : entry->shared_secret_len = shared_secret_len;
673 7862 : os_get_reltime(&entry->last_attempt);
674 7862 : entry->first_try = entry->last_attempt.sec;
675 7862 : entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
676 7862 : entry->attempts = 1;
677 7862 : entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
678 7862 : entry->next = radius->msgs;
679 7862 : radius->msgs = entry;
680 7862 : radius_client_update_timeout(radius);
681 :
682 7862 : if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
683 12 : wpa_printf(MSG_INFO, "RADIUS: Removing the oldest un-ACKed packet due to retransmit list limits");
684 12 : prev = NULL;
685 384 : while (entry->next) {
686 360 : prev = entry;
687 360 : entry = entry->next;
688 : }
689 12 : if (prev) {
690 12 : prev->next = NULL;
691 12 : radius_client_msg_free(entry);
692 : }
693 : } else
694 7850 : 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 : */
723 7877 : int radius_client_send(struct radius_client_data *radius,
724 : struct radius_msg *msg, RadiusType msg_type,
725 : const u8 *addr)
726 : {
727 7877 : 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 7877 : if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
735 597 : if (conf->acct_server && radius->acct_sock < 0)
736 7 : radius_client_init_acct(radius);
737 :
738 1188 : if (conf->acct_server == NULL || radius->acct_sock < 0 ||
739 591 : conf->acct_server->shared_secret == NULL) {
740 8 : hostapd_logger(radius->ctx, NULL,
741 : HOSTAPD_MODULE_RADIUS,
742 : HOSTAPD_LEVEL_INFO,
743 : "No accounting server configured");
744 8 : return -1;
745 : }
746 589 : shared_secret = conf->acct_server->shared_secret;
747 589 : shared_secret_len = conf->acct_server->shared_secret_len;
748 589 : radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
749 589 : name = "accounting";
750 589 : s = radius->acct_sock;
751 589 : conf->acct_server->requests++;
752 : } else {
753 7280 : if (conf->auth_server && radius->auth_sock < 0)
754 3 : radius_client_init_auth(radius);
755 :
756 14558 : if (conf->auth_server == NULL || radius->auth_sock < 0 ||
757 7278 : conf->auth_server->shared_secret == NULL) {
758 2 : hostapd_logger(radius->ctx, NULL,
759 : HOSTAPD_MODULE_RADIUS,
760 : HOSTAPD_LEVEL_INFO,
761 : "No authentication server configured");
762 2 : return -1;
763 : }
764 7278 : shared_secret = conf->auth_server->shared_secret;
765 7278 : shared_secret_len = conf->auth_server->shared_secret_len;
766 7278 : radius_msg_finish(msg, shared_secret, shared_secret_len);
767 7278 : name = "authentication";
768 7278 : s = radius->auth_sock;
769 7278 : conf->auth_server->requests++;
770 : }
771 :
772 7867 : hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
773 : HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
774 : "server", name);
775 7867 : if (conf->msg_dumps)
776 7867 : radius_msg_dump(msg);
777 :
778 7867 : buf = radius_msg_get_buf(msg);
779 7867 : res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0);
780 7867 : if (res < 0)
781 3 : radius_client_handle_send_error(radius, s, msg_type);
782 :
783 7867 : radius_client_list_add(radius, msg, msg_type, shared_secret,
784 : shared_secret_len, addr);
785 :
786 7867 : return 0;
787 : }
788 :
789 :
790 7813 : static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
791 : {
792 7813 : struct radius_client_data *radius = eloop_ctx;
793 7813 : struct hostapd_radius_servers *conf = radius->conf;
794 7813 : 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 7813 : int invalid_authenticator = 0;
805 :
806 7813 : if (msg_type == RADIUS_ACCT) {
807 528 : handlers = radius->acct_handlers;
808 528 : num_handlers = radius->num_acct_handlers;
809 528 : rconf = conf->acct_server;
810 : } else {
811 7285 : handlers = radius->auth_handlers;
812 7285 : num_handlers = radius->num_auth_handlers;
813 7285 : rconf = conf->auth_server;
814 : }
815 :
816 7813 : len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
817 7813 : if (len < 0) {
818 61 : wpa_printf(MSG_INFO, "recv[RADIUS]: %s", strerror(errno));
819 61 : return;
820 : }
821 7752 : hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
822 : HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
823 : "server", len);
824 7752 : if (len == sizeof(buf)) {
825 0 : wpa_printf(MSG_INFO, "RADIUS: Possibly too long UDP frame for our buffer - dropping it");
826 0 : return;
827 : }
828 :
829 7752 : msg = radius_msg_parse(buf, len);
830 7752 : if (msg == NULL) {
831 18 : wpa_printf(MSG_INFO, "RADIUS: Parsing incoming frame failed");
832 18 : rconf->malformed_responses++;
833 18 : return;
834 : }
835 7734 : hdr = radius_msg_get_hdr(msg);
836 :
837 7734 : hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
838 : HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
839 7734 : if (conf->msg_dumps)
840 7734 : radius_msg_dump(msg);
841 :
842 7734 : switch (hdr->code) {
843 : case RADIUS_CODE_ACCESS_ACCEPT:
844 1150 : rconf->access_accepts++;
845 1150 : break;
846 : case RADIUS_CODE_ACCESS_REJECT:
847 267 : rconf->access_rejects++;
848 267 : break;
849 : case RADIUS_CODE_ACCESS_CHALLENGE:
850 5850 : rconf->access_challenges++;
851 5850 : break;
852 : case RADIUS_CODE_ACCOUNTING_RESPONSE:
853 467 : rconf->responses++;
854 467 : break;
855 : }
856 :
857 7734 : prev_req = NULL;
858 7734 : req = radius->msgs;
859 16940 : while (req) {
860 : /* TODO: also match by src addr:port of the packet when using
861 : * alternative RADIUS servers (?) */
862 9091 : if ((req->msg_type == msg_type ||
863 6 : (req->msg_type == RADIUS_ACCT_INTERIM &&
864 9088 : msg_type == RADIUS_ACCT)) &&
865 9088 : radius_msg_get_hdr(req->msg)->identifier ==
866 9088 : hdr->identifier)
867 7616 : break;
868 :
869 1472 : prev_req = req;
870 1472 : req = req->next;
871 : }
872 :
873 7734 : if (req == NULL) {
874 118 : 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 118 : msg_type, hdr->identifier);
879 118 : goto fail;
880 : }
881 :
882 7616 : os_get_reltime(&now);
883 15232 : roundtrip = (now.sec - req->last_attempt.sec) * 100 +
884 7616 : (now.usec - req->last_attempt.usec) / 10000;
885 7616 : 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 7616 : rconf->round_trip_time = roundtrip;
891 :
892 : /* Remove ACKed RADIUS packet from retransmit list */
893 7616 : if (prev_req)
894 1146 : prev_req->next = req->next;
895 : else
896 6470 : radius->msgs = req->next;
897 7616 : radius->num_msgs--;
898 :
899 14765 : for (i = 0; i < num_handlers; i++) {
900 : RadiusRxResult res;
901 29514 : res = handlers[i].handler(msg, req->msg, req->shared_secret,
902 : req->shared_secret_len,
903 14757 : handlers[i].data);
904 14757 : switch (res) {
905 : case RADIUS_RX_PROCESSED:
906 473 : radius_msg_free(msg);
907 : /* continue */
908 : case RADIUS_RX_QUEUED:
909 7608 : radius_client_msg_free(req);
910 7608 : return;
911 : case RADIUS_RX_INVALID_AUTHENTICATOR:
912 8 : invalid_authenticator++;
913 : /* continue */
914 : case RADIUS_RX_UNKNOWN:
915 : /* continue with next handler */
916 7149 : break;
917 : }
918 : }
919 :
920 8 : if (invalid_authenticator)
921 8 : rconf->bad_authenticators++;
922 : else
923 0 : rconf->unknown_types++;
924 24 : 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 16 : msg_type, hdr->code, hdr->identifier,
928 : invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
929 : "");
930 8 : radius_client_msg_free(req);
931 :
932 : fail:
933 126 : 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 : */
945 7901 : u8 radius_client_get_id(struct radius_client_data *radius)
946 : {
947 : struct radius_msg_list *entry, *prev, *_remove;
948 7901 : 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 7901 : entry = radius->msgs;
953 7901 : prev = NULL;
954 19585 : while (entry) {
955 3783 : if (radius_msg_get_hdr(entry->msg)->identifier == id) {
956 0 : 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 0 : if (prev)
962 0 : prev->next = entry->next;
963 : else
964 0 : radius->msgs = entry->next;
965 0 : _remove = entry;
966 : } else {
967 3783 : _remove = NULL;
968 3783 : prev = entry;
969 : }
970 3783 : entry = entry->next;
971 :
972 3783 : if (_remove)
973 0 : radius_client_msg_free(_remove);
974 : }
975 :
976 7901 : 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 : */
985 2066 : void radius_client_flush(struct radius_client_data *radius, int only_auth)
986 : {
987 : struct radius_msg_list *entry, *prev, *tmp;
988 :
989 2066 : if (!radius)
990 2066 : return;
991 :
992 2066 : prev = NULL;
993 2066 : entry = radius->msgs;
994 :
995 4240 : while (entry) {
996 108 : if (!only_auth || entry->msg_type == RADIUS_AUTH) {
997 107 : if (prev)
998 0 : prev->next = entry->next;
999 : else
1000 107 : radius->msgs = entry->next;
1001 :
1002 107 : tmp = entry;
1003 107 : entry = entry->next;
1004 107 : radius_client_msg_free(tmp);
1005 107 : radius->num_msgs--;
1006 : } else {
1007 1 : prev = entry;
1008 1 : entry = entry->next;
1009 : }
1010 : }
1011 :
1012 2066 : if (radius->msgs == NULL)
1013 2065 : eloop_cancel_timeout(radius_client_timer, radius, NULL);
1014 : }
1015 :
1016 :
1017 2 : 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 2 : if (!radius)
1024 2 : return;
1025 :
1026 3 : for (entry = radius->msgs; entry; entry = entry->next) {
1027 1 : if (entry->msg_type == RADIUS_ACCT) {
1028 1 : entry->shared_secret = shared_secret;
1029 1 : entry->shared_secret_len = shared_secret_len;
1030 1 : radius_msg_finish_acct(entry->msg, shared_secret,
1031 : shared_secret_len);
1032 : }
1033 : }
1034 : }
1035 :
1036 :
1037 : static int
1038 652 : 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 652 : struct hostapd_radius_servers *conf = radius->conf;
1053 652 : struct sockaddr_in disconnect_addr = {
1054 : .sin_family = AF_UNSPEC,
1055 : };
1056 :
1057 1304 : hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
1058 : HOSTAPD_LEVEL_INFO,
1059 : "%s server %s:%d",
1060 : auth ? "Authentication" : "Accounting",
1061 652 : hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
1062 : nserv->port);
1063 :
1064 652 : if (oserv && oserv == nserv) {
1065 : /* Reconnect to same server, flush */
1066 2 : if (auth)
1067 1 : radius_client_flush(radius, 1);
1068 : }
1069 :
1070 656 : if (oserv && oserv != nserv &&
1071 4 : (nserv->shared_secret_len != oserv->shared_secret_len ||
1072 0 : 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 4 : if (auth)
1082 2 : radius_client_flush(radius, 1);
1083 : else {
1084 4 : radius_client_update_acct_msgs(
1085 2 : radius, nserv->shared_secret,
1086 : nserv->shared_secret_len);
1087 : }
1088 : }
1089 :
1090 : /* Reset retry counters for the new server */
1091 1306 : for (entry = radius->msgs; oserv && oserv != nserv && entry;
1092 2 : entry = entry->next) {
1093 2 : if ((auth && entry->msg_type != RADIUS_AUTH) ||
1094 1 : (!auth && entry->msg_type != RADIUS_ACCT))
1095 1 : continue;
1096 1 : entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
1097 1 : entry->attempts = 0;
1098 1 : entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
1099 : }
1100 :
1101 652 : if (radius->msgs) {
1102 8 : eloop_cancel_timeout(radius_client_timer, radius, NULL);
1103 8 : eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
1104 : radius_client_timer, radius, NULL);
1105 : }
1106 :
1107 652 : switch (nserv->addr.af) {
1108 : case AF_INET:
1109 649 : os_memset(&serv, 0, sizeof(serv));
1110 649 : serv.sin_family = AF_INET;
1111 649 : serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
1112 649 : serv.sin_port = htons(nserv->port);
1113 649 : addr = (struct sockaddr *) &serv;
1114 649 : addrlen = sizeof(serv);
1115 649 : sel_sock = sock;
1116 649 : break;
1117 : #ifdef CONFIG_IPV6
1118 : case AF_INET6:
1119 2 : os_memset(&serv6, 0, sizeof(serv6));
1120 2 : serv6.sin6_family = AF_INET6;
1121 2 : os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
1122 : sizeof(struct in6_addr));
1123 2 : serv6.sin6_port = htons(nserv->port);
1124 2 : addr = (struct sockaddr *) &serv6;
1125 2 : addrlen = sizeof(serv6);
1126 2 : sel_sock = sock6;
1127 2 : break;
1128 : #endif /* CONFIG_IPV6 */
1129 : default:
1130 1 : return -1;
1131 : }
1132 :
1133 651 : if (sel_sock < 0) {
1134 0 : 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 0 : return -1;
1138 : }
1139 :
1140 651 : if (conf->force_client_addr) {
1141 3 : switch (conf->client_addr.af) {
1142 : case AF_INET:
1143 1 : os_memset(&claddr, 0, sizeof(claddr));
1144 1 : claddr.sin_family = AF_INET;
1145 1 : claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
1146 1 : claddr.sin_port = htons(0);
1147 1 : cl_addr = (struct sockaddr *) &claddr;
1148 1 : claddrlen = sizeof(claddr);
1149 1 : break;
1150 : #ifdef CONFIG_IPV6
1151 : case AF_INET6:
1152 2 : os_memset(&claddr6, 0, sizeof(claddr6));
1153 2 : claddr6.sin6_family = AF_INET6;
1154 2 : os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
1155 : sizeof(struct in6_addr));
1156 2 : claddr6.sin6_port = htons(0);
1157 2 : cl_addr = (struct sockaddr *) &claddr6;
1158 2 : claddrlen = sizeof(claddr6);
1159 2 : break;
1160 : #endif /* CONFIG_IPV6 */
1161 : default:
1162 0 : return -1;
1163 : }
1164 :
1165 3 : if (bind(sel_sock, cl_addr, claddrlen) < 0) {
1166 2 : wpa_printf(MSG_INFO, "bind[radius]: %s",
1167 2 : strerror(errno));
1168 2 : return -1;
1169 : }
1170 : }
1171 :
1172 : /* Force a reconnect by disconnecting the socket first */
1173 649 : if (connect(sel_sock, (struct sockaddr *) &disconnect_addr,
1174 : sizeof(disconnect_addr)) < 0)
1175 0 : wpa_printf(MSG_INFO, "disconnect[radius]: %s", strerror(errno));
1176 :
1177 649 : if (connect(sel_sock, addr, addrlen) < 0) {
1178 17 : wpa_printf(MSG_INFO, "connect[radius]: %s", strerror(errno));
1179 17 : return -1;
1180 : }
1181 :
1182 : #ifndef CONFIG_NATIVE_WINDOWS
1183 632 : switch (nserv->addr.af) {
1184 : case AF_INET:
1185 630 : claddrlen = sizeof(claddr);
1186 630 : if (getsockname(sel_sock, (struct sockaddr *) &claddr,
1187 : &claddrlen) == 0) {
1188 630 : wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1189 : inet_ntoa(claddr.sin_addr),
1190 630 : ntohs(claddr.sin_port));
1191 : }
1192 630 : break;
1193 : #ifdef CONFIG_IPV6
1194 : case AF_INET6: {
1195 2 : claddrlen = sizeof(claddr6);
1196 2 : if (getsockname(sel_sock, (struct sockaddr *) &claddr6,
1197 : &claddrlen) == 0) {
1198 2 : wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
1199 : inet_ntop(AF_INET6, &claddr6.sin6_addr,
1200 : abuf, sizeof(abuf)),
1201 2 : ntohs(claddr6.sin6_port));
1202 : }
1203 2 : break;
1204 : }
1205 : #endif /* CONFIG_IPV6 */
1206 : }
1207 : #endif /* CONFIG_NATIVE_WINDOWS */
1208 :
1209 632 : if (auth)
1210 567 : radius->auth_sock = sel_sock;
1211 : else
1212 65 : radius->acct_sock = sel_sock;
1213 :
1214 632 : return 0;
1215 : }
1216 :
1217 :
1218 1 : static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
1219 : {
1220 1 : struct radius_client_data *radius = eloop_ctx;
1221 1 : struct hostapd_radius_servers *conf = radius->conf;
1222 : struct hostapd_radius_server *oserv;
1223 :
1224 2 : if (radius->auth_sock >= 0 && conf->auth_servers &&
1225 1 : conf->auth_server != conf->auth_servers) {
1226 1 : oserv = conf->auth_server;
1227 1 : conf->auth_server = conf->auth_servers;
1228 1 : if (radius_change_server(radius, conf->auth_server, oserv,
1229 : radius->auth_serv_sock,
1230 : radius->auth_serv_sock6, 1) < 0) {
1231 1 : conf->auth_server = oserv;
1232 1 : radius_change_server(radius, oserv, conf->auth_server,
1233 : radius->auth_serv_sock,
1234 : radius->auth_serv_sock6, 1);
1235 : }
1236 : }
1237 :
1238 2 : if (radius->acct_sock >= 0 && conf->acct_servers &&
1239 1 : conf->acct_server != conf->acct_servers) {
1240 1 : oserv = conf->acct_server;
1241 1 : conf->acct_server = conf->acct_servers;
1242 1 : if (radius_change_server(radius, conf->acct_server, oserv,
1243 : radius->acct_serv_sock,
1244 : radius->acct_serv_sock6, 0) < 0) {
1245 1 : conf->acct_server = oserv;
1246 1 : radius_change_server(radius, oserv, conf->acct_server,
1247 : radius->acct_serv_sock,
1248 : radius->acct_serv_sock6, 0);
1249 : }
1250 : }
1251 :
1252 1 : if (conf->retry_primary_interval)
1253 1 : eloop_register_timeout(conf->retry_primary_interval, 0,
1254 : radius_retry_primary_timer, radius,
1255 : NULL);
1256 1 : }
1257 :
1258 :
1259 646 : static int radius_client_disable_pmtu_discovery(int s)
1260 : {
1261 646 : int r = -1;
1262 : #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
1263 : /* Turn off Path MTU discovery on IPv4/UDP sockets. */
1264 646 : int action = IP_PMTUDISC_DONT;
1265 646 : r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
1266 : sizeof(action));
1267 646 : if (r == -1)
1268 0 : wpa_printf(MSG_ERROR, "RADIUS: Failed to set IP_MTU_DISCOVER: %s",
1269 0 : strerror(errno));
1270 : #endif
1271 646 : return r;
1272 : }
1273 :
1274 :
1275 2614 : static void radius_close_auth_sockets(struct radius_client_data *radius)
1276 : {
1277 2614 : radius->auth_sock = -1;
1278 :
1279 2614 : if (radius->auth_serv_sock >= 0) {
1280 572 : eloop_unregister_read_sock(radius->auth_serv_sock);
1281 572 : close(radius->auth_serv_sock);
1282 572 : radius->auth_serv_sock = -1;
1283 : }
1284 : #ifdef CONFIG_IPV6
1285 2614 : if (radius->auth_serv_sock6 >= 0) {
1286 572 : eloop_unregister_read_sock(radius->auth_serv_sock6);
1287 572 : close(radius->auth_serv_sock6);
1288 572 : radius->auth_serv_sock6 = -1;
1289 : }
1290 : #endif /* CONFIG_IPV6 */
1291 2614 : }
1292 :
1293 :
1294 2116 : static void radius_close_acct_sockets(struct radius_client_data *radius)
1295 : {
1296 2116 : radius->acct_sock = -1;
1297 :
1298 2116 : if (radius->acct_serv_sock >= 0) {
1299 74 : eloop_unregister_read_sock(radius->acct_serv_sock);
1300 74 : close(radius->acct_serv_sock);
1301 74 : radius->acct_serv_sock = -1;
1302 : }
1303 : #ifdef CONFIG_IPV6
1304 2116 : if (radius->acct_serv_sock6 >= 0) {
1305 74 : eloop_unregister_read_sock(radius->acct_serv_sock6);
1306 74 : close(radius->acct_serv_sock6);
1307 74 : radius->acct_serv_sock6 = -1;
1308 : }
1309 : #endif /* CONFIG_IPV6 */
1310 2116 : }
1311 :
1312 :
1313 572 : static int radius_client_init_auth(struct radius_client_data *radius)
1314 : {
1315 572 : struct hostapd_radius_servers *conf = radius->conf;
1316 572 : int ok = 0;
1317 :
1318 572 : radius_close_auth_sockets(radius);
1319 :
1320 572 : radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1321 572 : if (radius->auth_serv_sock < 0)
1322 0 : wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1323 0 : strerror(errno));
1324 : else {
1325 572 : radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
1326 572 : ok++;
1327 : }
1328 :
1329 : #ifdef CONFIG_IPV6
1330 572 : radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1331 572 : if (radius->auth_serv_sock6 < 0)
1332 0 : wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1333 0 : strerror(errno));
1334 : else
1335 572 : ok++;
1336 : #endif /* CONFIG_IPV6 */
1337 :
1338 572 : if (ok == 0)
1339 0 : return -1;
1340 :
1341 572 : radius_change_server(radius, conf->auth_server, NULL,
1342 : radius->auth_serv_sock, radius->auth_serv_sock6,
1343 : 1);
1344 :
1345 1144 : if (radius->auth_serv_sock >= 0 &&
1346 572 : eloop_register_read_sock(radius->auth_serv_sock,
1347 : radius_client_receive, radius,
1348 : (void *) RADIUS_AUTH)) {
1349 0 : wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1350 0 : radius_close_auth_sockets(radius);
1351 0 : return -1;
1352 : }
1353 :
1354 : #ifdef CONFIG_IPV6
1355 1144 : if (radius->auth_serv_sock6 >= 0 &&
1356 572 : eloop_register_read_sock(radius->auth_serv_sock6,
1357 : radius_client_receive, radius,
1358 : (void *) RADIUS_AUTH)) {
1359 0 : wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for authentication server");
1360 0 : radius_close_auth_sockets(radius);
1361 0 : return -1;
1362 : }
1363 : #endif /* CONFIG_IPV6 */
1364 :
1365 572 : return 0;
1366 : }
1367 :
1368 :
1369 74 : static int radius_client_init_acct(struct radius_client_data *radius)
1370 : {
1371 74 : struct hostapd_radius_servers *conf = radius->conf;
1372 74 : int ok = 0;
1373 :
1374 74 : radius_close_acct_sockets(radius);
1375 :
1376 74 : radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
1377 74 : if (radius->acct_serv_sock < 0)
1378 0 : wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET,SOCK_DGRAM]: %s",
1379 0 : strerror(errno));
1380 : else {
1381 74 : radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
1382 74 : ok++;
1383 : }
1384 :
1385 : #ifdef CONFIG_IPV6
1386 74 : radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
1387 74 : if (radius->acct_serv_sock6 < 0)
1388 0 : wpa_printf(MSG_INFO, "RADIUS: socket[PF_INET6,SOCK_DGRAM]: %s",
1389 0 : strerror(errno));
1390 : else
1391 74 : ok++;
1392 : #endif /* CONFIG_IPV6 */
1393 :
1394 74 : if (ok == 0)
1395 0 : return -1;
1396 :
1397 74 : radius_change_server(radius, conf->acct_server, NULL,
1398 : radius->acct_serv_sock, radius->acct_serv_sock6,
1399 : 0);
1400 :
1401 148 : if (radius->acct_serv_sock >= 0 &&
1402 74 : eloop_register_read_sock(radius->acct_serv_sock,
1403 : radius_client_receive, radius,
1404 : (void *) RADIUS_ACCT)) {
1405 0 : wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1406 0 : radius_close_acct_sockets(radius);
1407 0 : return -1;
1408 : }
1409 :
1410 : #ifdef CONFIG_IPV6
1411 148 : if (radius->acct_serv_sock6 >= 0 &&
1412 74 : eloop_register_read_sock(radius->acct_serv_sock6,
1413 : radius_client_receive, radius,
1414 : (void *) RADIUS_ACCT)) {
1415 0 : wpa_printf(MSG_INFO, "RADIUS: Could not register read socket for accounting server");
1416 0 : radius_close_acct_sockets(radius);
1417 0 : return -1;
1418 : }
1419 : #endif /* CONFIG_IPV6 */
1420 :
1421 74 : 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 *
1436 2042 : radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
1437 : {
1438 : struct radius_client_data *radius;
1439 :
1440 2042 : radius = os_zalloc(sizeof(struct radius_client_data));
1441 2042 : if (radius == NULL)
1442 0 : return NULL;
1443 :
1444 2042 : radius->ctx = ctx;
1445 2042 : radius->conf = conf;
1446 2042 : radius->auth_serv_sock = radius->acct_serv_sock =
1447 2042 : radius->auth_serv_sock6 = radius->acct_serv_sock6 =
1448 2042 : radius->auth_sock = radius->acct_sock = -1;
1449 :
1450 2042 : if (conf->auth_server && radius_client_init_auth(radius)) {
1451 0 : radius_client_deinit(radius);
1452 0 : return NULL;
1453 : }
1454 :
1455 2042 : if (conf->acct_server && radius_client_init_acct(radius)) {
1456 0 : radius_client_deinit(radius);
1457 0 : return NULL;
1458 : }
1459 :
1460 2042 : if (conf->retry_primary_interval)
1461 1 : eloop_register_timeout(conf->retry_primary_interval, 0,
1462 : radius_retry_primary_timer, radius,
1463 : NULL);
1464 :
1465 2042 : return radius;
1466 : }
1467 :
1468 :
1469 : /**
1470 : * radius_client_deinit - Deinitialize RADIUS client
1471 : * @radius: RADIUS client context from radius_client_init()
1472 : */
1473 2046 : void radius_client_deinit(struct radius_client_data *radius)
1474 : {
1475 2046 : if (!radius)
1476 2050 : return;
1477 :
1478 2042 : radius_close_auth_sockets(radius);
1479 2042 : radius_close_acct_sockets(radius);
1480 :
1481 2042 : eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
1482 :
1483 2042 : radius_client_flush(radius, 0);
1484 2042 : os_free(radius->auth_handlers);
1485 2042 : os_free(radius->acct_handlers);
1486 2042 : 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 : */
1500 3799 : 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 3799 : prev = NULL;
1506 3799 : entry = radius->msgs;
1507 8657 : while (entry) {
1508 1260 : if (entry->msg_type == RADIUS_AUTH &&
1509 201 : os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
1510 122 : 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 122 : if (prev)
1517 0 : prev->next = entry->next;
1518 : else
1519 122 : radius->msgs = entry->next;
1520 :
1521 122 : tmp = entry;
1522 122 : entry = entry->next;
1523 122 : radius_client_msg_free(tmp);
1524 122 : radius->num_msgs--;
1525 122 : continue;
1526 : }
1527 :
1528 937 : prev = entry;
1529 937 : entry = entry->next;
1530 : }
1531 3799 : }
1532 :
1533 :
1534 10 : 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 10 : int pending = 0;
1539 : struct radius_msg_list *msg;
1540 : char abuf[50];
1541 :
1542 10 : if (cli) {
1543 25 : for (msg = cli->msgs; msg; msg = msg->next) {
1544 15 : if (msg->msg_type == RADIUS_AUTH)
1545 1 : pending++;
1546 : }
1547 : }
1548 :
1549 20 : 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 10 : 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 :
1583 8 : 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 8 : int pending = 0;
1588 : struct radius_msg_list *msg;
1589 : char abuf[50];
1590 :
1591 8 : if (cli) {
1592 22 : for (msg = cli->msgs; msg; msg = msg->next) {
1593 18 : if (msg->msg_type == RADIUS_ACCT ||
1594 4 : msg->msg_type == RADIUS_ACCT_INTERIM)
1595 14 : pending++;
1596 : }
1597 : }
1598 :
1599 16 : 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 8 : 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 : */
1636 13 : int radius_client_get_mib(struct radius_client_data *radius, char *buf,
1637 : size_t buflen)
1638 : {
1639 : struct hostapd_radius_servers *conf;
1640 : int i;
1641 : struct hostapd_radius_server *serv;
1642 13 : int count = 0;
1643 :
1644 13 : if (!radius)
1645 1 : return 0;
1646 :
1647 12 : conf = radius->conf;
1648 :
1649 12 : if (conf->auth_servers) {
1650 20 : for (i = 0; i < conf->num_auth_servers; i++) {
1651 10 : serv = &conf->auth_servers[i];
1652 10 : count += radius_client_dump_auth_server(
1653 : buf + count, buflen - count, serv,
1654 10 : serv == conf->auth_server ?
1655 : radius : NULL);
1656 : }
1657 : }
1658 :
1659 12 : if (conf->acct_servers) {
1660 16 : for (i = 0; i < conf->num_acct_servers; i++) {
1661 8 : serv = &conf->acct_servers[i];
1662 8 : count += radius_client_dump_acct_server(
1663 : buf + count, buflen - count, serv,
1664 8 : serv == conf->acct_server ?
1665 : radius : NULL);
1666 : }
1667 : }
1668 :
1669 12 : return count;
1670 : }
1671 :
1672 :
1673 21 : void radius_client_reconfig(struct radius_client_data *radius,
1674 : struct hostapd_radius_servers *conf)
1675 : {
1676 21 : if (radius)
1677 21 : radius->conf = conf;
1678 21 : }
|