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