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