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