1 /* 2 * hostapd / RADIUS client 3 * Copyright (c) 2002-2005, Jouni Malinen <j (at) w1.fi> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License version 2 as 7 * published by the Free Software Foundation. 8 * 9 * Alternatively, this software may be distributed under the terms of BSD 10 * license. 11 * 12 * See README and COPYING for more details. 13 */ 14 15 #include "includes.h" 16 17 #include "hostapd.h" 18 #include "radius.h" 19 #include "radius_client.h" 20 #include "eloop.h" 21 22 /* Defaults for RADIUS retransmit values (exponential backoff) */ 23 #define RADIUS_CLIENT_FIRST_WAIT 3 /* seconds */ 24 #define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */ 25 #define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts 26 * before entry is removed from retransmit 27 * list */ 28 #define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit 29 * list (oldest will be removed, if this 30 * limit is exceeded) */ 31 #define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this 32 * many failed retry attempts */ 33 34 35 struct radius_rx_handler { 36 RadiusRxResult (*handler)(struct radius_msg *msg, 37 struct radius_msg *req, 38 u8 *shared_secret, size_t shared_secret_len, 39 void *data); 40 void *data; 41 }; 42 43 44 /* RADIUS message retransmit list */ 45 struct radius_msg_list { 46 u8 addr[ETH_ALEN]; /* STA/client address; used to find RADIUS messages 47 * for the same STA. */ 48 struct radius_msg *msg; 49 RadiusType msg_type; 50 os_time_t first_try; 51 os_time_t next_try; 52 int attempts; 53 int next_wait; 54 struct os_time last_attempt; 55 56 u8 *shared_secret; 57 size_t shared_secret_len; 58 59 /* TODO: server config with failover to backup server(s) */ 60 61 struct radius_msg_list *next; 62 }; 63 64 65 struct radius_client_data { 66 void *ctx; 67 struct hostapd_radius_servers *conf; 68 69 int auth_serv_sock; /* socket for authentication RADIUS messages */ 70 int acct_serv_sock; /* socket for accounting RADIUS messages */ 71 int auth_serv_sock6; 72 int acct_serv_sock6; 73 int auth_sock; /* currently used socket */ 74 int acct_sock; /* currently used socket */ 75 76 struct radius_rx_handler *auth_handlers; 77 size_t num_auth_handlers; 78 struct radius_rx_handler *acct_handlers; 79 size_t num_acct_handlers; 80 81 struct radius_msg_list *msgs; 82 size_t num_msgs; 83 84 u8 next_radius_identifier; 85 }; 86 87 88 static int 89 radius_change_server(struct radius_client_data *radius, 90 struct hostapd_radius_server *nserv, 91 struct hostapd_radius_server *oserv, 92 int sock, int sock6, int auth); 93 static int radius_client_init_acct(struct radius_client_data *radius); 94 static int radius_client_init_auth(struct radius_client_data *radius); 95 96 97 static void radius_client_msg_free(struct radius_msg_list *req) 98 { 99 radius_msg_free(req->msg); 100 os_free(req->msg); 101 os_free(req); 102 } 103 104 105 int radius_client_register(struct radius_client_data *radius, 106 RadiusType msg_type, 107 RadiusRxResult (*handler)(struct radius_msg *msg, 108 struct radius_msg *req, 109 u8 *shared_secret, 110 size_t shared_secret_len, 111 void *data), 112 void *data) 113 { 114 struct radius_rx_handler **handlers, *newh; 115 size_t *num; 116 117 if (msg_type == RADIUS_ACCT) { 118 handlers = &radius->acct_handlers; 119 num = &radius->num_acct_handlers; 120 } else { 121 handlers = &radius->auth_handlers; 122 num = &radius->num_auth_handlers; 123 } 124 125 newh = os_realloc(*handlers, 126 (*num + 1) * sizeof(struct radius_rx_handler)); 127 if (newh == NULL) 128 return -1; 129 130 newh[*num].handler = handler; 131 newh[*num].data = data; 132 (*num)++; 133 *handlers = newh; 134 135 return 0; 136 } 137 138 139 static void radius_client_handle_send_error(struct radius_client_data *radius, 140 int s, RadiusType msg_type) 141 { 142 #ifndef CONFIG_NATIVE_WINDOWS 143 int _errno = errno; 144 perror("send[RADIUS]"); 145 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || 146 _errno == EBADF) { 147 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 148 HOSTAPD_LEVEL_INFO, 149 "Send failed - maybe interface status changed -" 150 " try to connect again"); 151 eloop_unregister_read_sock(s); 152 close(s); 153 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) 154 radius_client_init_acct(radius); 155 else 156 radius_client_init_auth(radius); 157 } 158 #endif /* CONFIG_NATIVE_WINDOWS */ 159 } 160 161 162 static int radius_client_retransmit(struct radius_client_data *radius, 163 struct radius_msg_list *entry, 164 os_time_t now) 165 { 166 struct hostapd_radius_servers *conf = radius->conf; 167 int s; 168 169 if (entry->msg_type == RADIUS_ACCT || 170 entry->msg_type == RADIUS_ACCT_INTERIM) { 171 s = radius->acct_sock; 172 if (entry->attempts == 0) 173 conf->acct_server->requests++; 174 else { 175 conf->acct_server->timeouts++; 176 conf->acct_server->retransmissions++; 177 } 178 } else { 179 s = radius->auth_sock; 180 if (entry->attempts == 0) 181 conf->auth_server->requests++; 182 else { 183 conf->auth_server->timeouts++; 184 conf->auth_server->retransmissions++; 185 } 186 } 187 188 /* retransmit; remove entry if too many attempts */ 189 entry->attempts++; 190 hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, 191 HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", 192 entry->msg->hdr->identifier); 193 194 os_get_time(&entry->last_attempt); 195 if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0) 196 radius_client_handle_send_error(radius, s, entry->msg_type); 197 198 entry->next_try = now + entry->next_wait; 199 entry->next_wait *= 2; 200 if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT) 201 entry->next_wait = RADIUS_CLIENT_MAX_WAIT; 202 if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) { 203 printf("Removing un-ACKed RADIUS message due to too many " 204 "failed retransmit attempts\n"); 205 return 1; 206 } 207 208 return 0; 209 } 210 211 212 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) 213 { 214 struct radius_client_data *radius = eloop_ctx; 215 struct hostapd_radius_servers *conf = radius->conf; 216 struct os_time now; 217 os_time_t first; 218 struct radius_msg_list *entry, *prev, *tmp; 219 int auth_failover = 0, acct_failover = 0; 220 char abuf[50]; 221 222 entry = radius->msgs; 223 if (!entry) 224 return; 225 226 os_get_time(&now); 227 first = 0; 228 229 prev = NULL; 230 while (entry) { 231 if (now.sec >= entry->next_try && 232 radius_client_retransmit(radius, entry, now.sec)) { 233 if (prev) 234 prev->next = entry->next; 235 else 236 radius->msgs = entry->next; 237 238 tmp = entry; 239 entry = entry->next; 240 radius_client_msg_free(tmp); 241 radius->num_msgs--; 242 continue; 243 } 244 245 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) { 246 if (entry->msg_type == RADIUS_ACCT || 247 entry->msg_type == RADIUS_ACCT_INTERIM) 248 acct_failover++; 249 else 250 auth_failover++; 251 } 252 253 if (first == 0 || entry->next_try < first) 254 first = entry->next_try; 255 256 prev = entry; 257 entry = entry->next; 258 } 259 260 if (radius->msgs) { 261 if (first < now.sec) 262 first = now.sec; 263 eloop_register_timeout(first - now.sec, 0, 264 radius_client_timer, radius, NULL); 265 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 266 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client " 267 "retransmit in %ld seconds", 268 (long int) (first - now.sec)); 269 } 270 271 if (auth_failover && conf->num_auth_servers > 1) { 272 struct hostapd_radius_server *next, *old; 273 old = conf->auth_server; 274 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 275 HOSTAPD_LEVEL_NOTICE, 276 "No response from Authentication server " 277 "%s:%d - failover", 278 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), 279 old->port); 280 281 for (entry = radius->msgs; entry; entry = entry->next) { 282 if (entry->msg_type == RADIUS_AUTH) 283 old->timeouts++; 284 } 285 286 next = old + 1; 287 if (next > &(conf->auth_servers[conf->num_auth_servers - 1])) 288 next = conf->auth_servers; 289 conf->auth_server = next; 290 radius_change_server(radius, next, old, 291 radius->auth_serv_sock, 292 radius->auth_serv_sock6, 1); 293 } 294 295 if (acct_failover && conf->num_acct_servers > 1) { 296 struct hostapd_radius_server *next, *old; 297 old = conf->acct_server; 298 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 299 HOSTAPD_LEVEL_NOTICE, 300 "No response from Accounting server " 301 "%s:%d - failover", 302 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), 303 old->port); 304 305 for (entry = radius->msgs; entry; entry = entry->next) { 306 if (entry->msg_type == RADIUS_ACCT || 307 entry->msg_type == RADIUS_ACCT_INTERIM) 308 old->timeouts++; 309 } 310 311 next = old + 1; 312 if (next > &conf->acct_servers[conf->num_acct_servers - 1]) 313 next = conf->acct_servers; 314 conf->acct_server = next; 315 radius_change_server(radius, next, old, 316 radius->acct_serv_sock, 317 radius->acct_serv_sock6, 0); 318 } 319 } 320 321 322 static void radius_client_update_timeout(struct radius_client_data *radius) 323 { 324 struct os_time now; 325 os_time_t first; 326 struct radius_msg_list *entry; 327 328 eloop_cancel_timeout(radius_client_timer, radius, NULL); 329 330 if (radius->msgs == NULL) { 331 return; 332 } 333 334 first = 0; 335 for (entry = radius->msgs; entry; entry = entry->next) { 336 if (first == 0 || entry->next_try < first) 337 first = entry->next_try; 338 } 339 340 os_get_time(&now); 341 if (first < now.sec) 342 first = now.sec; 343 eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius, 344 NULL); 345 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 346 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in" 347 " %ld seconds\n", (long int) (first - now.sec)); 348 } 349 350 351 static void radius_client_list_add(struct radius_client_data *radius, 352 struct radius_msg *msg, 353 RadiusType msg_type, u8 *shared_secret, 354 size_t shared_secret_len, const u8 *addr) 355 { 356 struct radius_msg_list *entry, *prev; 357 358 if (eloop_terminated()) { 359 /* No point in adding entries to retransmit queue since event 360 * loop has already been terminated. */ 361 radius_msg_free(msg); 362 os_free(msg); 363 return; 364 } 365 366 entry = wpa_zalloc(sizeof(*entry)); 367 if (entry == NULL) { 368 printf("Failed to add RADIUS packet into retransmit list\n"); 369 radius_msg_free(msg); 370 os_free(msg); 371 return; 372 } 373 374 if (addr) 375 os_memcpy(entry->addr, addr, ETH_ALEN); 376 entry->msg = msg; 377 entry->msg_type = msg_type; 378 entry->shared_secret = shared_secret; 379 entry->shared_secret_len = shared_secret_len; 380 os_get_time(&entry->last_attempt); 381 entry->first_try = entry->last_attempt.sec; 382 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; 383 entry->attempts = 1; 384 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; 385 entry->next = radius->msgs; 386 radius->msgs = entry; 387 radius_client_update_timeout(radius); 388 389 if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) { 390 printf("Removing the oldest un-ACKed RADIUS packet due to " 391 "retransmit list limits.\n"); 392 prev = NULL; 393 while (entry->next) { 394 prev = entry; 395 entry = entry->next; 396 } 397 if (prev) { 398 prev->next = NULL; 399 radius_client_msg_free(entry); 400 } 401 } else 402 radius->num_msgs++; 403 } 404 405 406 static void radius_client_list_del(struct radius_client_data *radius, 407 RadiusType msg_type, const u8 *addr) 408 { 409 struct radius_msg_list *entry, *prev, *tmp; 410 411 if (addr == NULL) 412 return; 413 414 entry = radius->msgs; 415 prev = NULL; 416 while (entry) { 417 if (entry->msg_type == msg_type && 418 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { 419 if (prev) 420 prev->next = entry->next; 421 else 422 radius->msgs = entry->next; 423 tmp = entry; 424 entry = entry->next; 425 hostapd_logger(radius->ctx, addr, 426 HOSTAPD_MODULE_RADIUS, 427 HOSTAPD_LEVEL_DEBUG, 428 "Removing matching RADIUS message"); 429 radius_client_msg_free(tmp); 430 radius->num_msgs--; 431 continue; 432 } 433 prev = entry; 434 entry = entry->next; 435 } 436 } 437 438 439 int radius_client_send(struct radius_client_data *radius, 440 struct radius_msg *msg, RadiusType msg_type, 441 const u8 *addr) 442 { 443 struct hostapd_radius_servers *conf = radius->conf; 444 u8 *shared_secret; 445 size_t shared_secret_len; 446 char *name; 447 int s, res; 448 449 if (msg_type == RADIUS_ACCT_INTERIM) { 450 /* Remove any pending interim acct update for the same STA. */ 451 radius_client_list_del(radius, msg_type, addr); 452 } 453 454 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) { 455 if (conf->acct_server == NULL) { 456 hostapd_logger(radius->ctx, NULL, 457 HOSTAPD_MODULE_RADIUS, 458 HOSTAPD_LEVEL_INFO, 459 "No accounting server configured"); 460 return -1; 461 } 462 shared_secret = conf->acct_server->shared_secret; 463 shared_secret_len = conf->acct_server->shared_secret_len; 464 radius_msg_finish_acct(msg, shared_secret, shared_secret_len); 465 name = "accounting"; 466 s = radius->acct_sock; 467 conf->acct_server->requests++; 468 } else { 469 if (conf->auth_server == NULL) { 470 hostapd_logger(radius->ctx, NULL, 471 HOSTAPD_MODULE_RADIUS, 472 HOSTAPD_LEVEL_INFO, 473 "No authentication server configured"); 474 return -1; 475 } 476 shared_secret = conf->auth_server->shared_secret; 477 shared_secret_len = conf->auth_server->shared_secret_len; 478 radius_msg_finish(msg, shared_secret, shared_secret_len); 479 name = "authentication"; 480 s = radius->auth_sock; 481 conf->auth_server->requests++; 482 } 483 484 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 485 HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s " 486 "server", name); 487 if (conf->msg_dumps) 488 radius_msg_dump(msg); 489 490 res = send(s, msg->buf, msg->buf_used, 0); 491 if (res < 0) 492 radius_client_handle_send_error(radius, s, msg_type); 493 494 radius_client_list_add(radius, msg, msg_type, shared_secret, 495 shared_secret_len, addr); 496 497 return res; 498 } 499 500 501 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) 502 { 503 struct radius_client_data *radius = eloop_ctx; 504 struct hostapd_radius_servers *conf = radius->conf; 505 RadiusType msg_type = (RadiusType) sock_ctx; 506 int len, roundtrip; 507 unsigned char buf[3000]; 508 struct radius_msg *msg; 509 struct radius_rx_handler *handlers; 510 size_t num_handlers, i; 511 struct radius_msg_list *req, *prev_req; 512 struct os_time now; 513 struct hostapd_radius_server *rconf; 514 int invalid_authenticator = 0; 515 516 if (msg_type == RADIUS_ACCT) { 517 handlers = radius->acct_handlers; 518 num_handlers = radius->num_acct_handlers; 519 rconf = conf->acct_server; 520 } else { 521 handlers = radius->auth_handlers; 522 num_handlers = radius->num_auth_handlers; 523 rconf = conf->auth_server; 524 } 525 526 len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT); 527 if (len < 0) { 528 perror("recv[RADIUS]"); 529 return; 530 } 531 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 532 HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS " 533 "server", len); 534 if (len == sizeof(buf)) { 535 printf("Possibly too long UDP frame for our buffer - " 536 "dropping it\n"); 537 return; 538 } 539 540 msg = radius_msg_parse(buf, len); 541 if (msg == NULL) { 542 printf("Parsing incoming RADIUS frame failed\n"); 543 rconf->malformed_responses++; 544 return; 545 } 546 547 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 548 HOSTAPD_LEVEL_DEBUG, "Received RADIUS message"); 549 if (conf->msg_dumps) 550 radius_msg_dump(msg); 551 552 switch (msg->hdr->code) { 553 case RADIUS_CODE_ACCESS_ACCEPT: 554 rconf->access_accepts++; 555 break; 556 case RADIUS_CODE_ACCESS_REJECT: 557 rconf->access_rejects++; 558 break; 559 case RADIUS_CODE_ACCESS_CHALLENGE: 560 rconf->access_challenges++; 561 break; 562 case RADIUS_CODE_ACCOUNTING_RESPONSE: 563 rconf->responses++; 564 break; 565 } 566 567 prev_req = NULL; 568 req = radius->msgs; 569 while (req) { 570 /* TODO: also match by src addr:port of the packet when using 571 * alternative RADIUS servers (?) */ 572 if ((req->msg_type == msg_type || 573 (req->msg_type == RADIUS_ACCT_INTERIM && 574 msg_type == RADIUS_ACCT)) && 575 req->msg->hdr->identifier == msg->hdr->identifier) 576 break; 577 578 prev_req = req; 579 req = req->next; 580 } 581 582 if (req == NULL) { 583 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 584 HOSTAPD_LEVEL_DEBUG, 585 "No matching RADIUS request found (type=%d " 586 "id=%d) - dropping packet", 587 msg_type, msg->hdr->identifier); 588 goto fail; 589 } 590 591 os_get_time(&now); 592 roundtrip = (now.sec - req->last_attempt.sec) * 100 + 593 (now.usec - req->last_attempt.usec) / 10000; 594 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, 595 HOSTAPD_LEVEL_DEBUG, 596 "Received RADIUS packet matched with a pending " 597 "request, round trip time %d.%02d sec", 598 roundtrip / 100, roundtrip % 100); 599 rconf->round_trip_time = roundtrip; 600 601 /* Remove ACKed RADIUS packet from retransmit list */ 602 if (prev_req) 603 prev_req->next = req->next; 604 else 605 radius->msgs = req->next; 606 radius->num_msgs--; 607 608 for (i = 0; i < num_handlers; i++) { 609 RadiusRxResult res; 610 res = handlers[i].handler(msg, req->msg, req->shared_secret, 611 req->shared_secret_len, 612 handlers[i].data); 613 switch (res) { 614 case RADIUS_RX_PROCESSED: 615 radius_msg_free(msg); 616 os_free(msg); 617 /* continue */ 618 case RADIUS_RX_QUEUED: 619 radius_client_msg_free(req); 620 return; 621 case RADIUS_RX_INVALID_AUTHENTICATOR: 622 invalid_authenticator++; 623 /* continue */ 624 case RADIUS_RX_UNKNOWN: 625 /* continue with next handler */ 626 break; 627 } 628 } 629 630 if (invalid_authenticator) 631 rconf->bad_authenticators++; 632 else 633 rconf->unknown_types++; 634 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, 635 HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found " 636 "(type=%d code=%d id=%d)%s - dropping packet", 637 msg_type, msg->hdr->code, msg->hdr->identifier, 638 invalid_authenticator ? " [INVALID AUTHENTICATOR]" : 639 ""); 640 radius_client_msg_free(req); 641 642 fail: 643 radius_msg_free(msg); 644 os_free(msg); 645 } 646 647 648 u8 radius_client_get_id(struct radius_client_data *radius) 649 { 650 struct radius_msg_list *entry, *prev, *_remove; 651 u8 id = radius->next_radius_identifier++; 652 653 /* remove entries with matching id from retransmit list to avoid 654 * using new reply from the RADIUS server with an old request */ 655 entry = radius->msgs; 656 prev = NULL; 657 while (entry) { 658 if (entry->msg->hdr->identifier == id) { 659 hostapd_logger(radius->ctx, entry->addr, 660 HOSTAPD_MODULE_RADIUS, 661 HOSTAPD_LEVEL_DEBUG, 662 "Removing pending RADIUS message, " 663 "since its id (%d) is reused", id); 664 if (prev) 665 prev->next = entry->next; 666 else 667 radius->msgs = entry->next; 668 _remove = entry; 669 } else { 670 _remove = NULL; 671 prev = entry; 672 } 673 entry = entry->next; 674 675 if (_remove) 676 radius_client_msg_free(_remove); 677 } 678 679 return id; 680 } 681 682 683 void radius_client_flush(struct radius_client_data *radius, int only_auth) 684 { 685 struct radius_msg_list *entry, *prev, *tmp; 686 687 if (!radius) 688 return; 689 690 prev = NULL; 691 entry = radius->msgs; 692 693 while (entry) { 694 if (!only_auth || entry->msg_type == RADIUS_AUTH) { 695 if (prev) 696 prev->next = entry->next; 697 else 698 radius->msgs = entry->next; 699 700 tmp = entry; 701 entry = entry->next; 702 radius_client_msg_free(tmp); 703 radius->num_msgs--; 704 } else { 705 prev = entry; 706 entry = entry->next; 707 } 708 } 709 710 if (radius->msgs == NULL) 711 eloop_cancel_timeout(radius_client_timer, radius, NULL); 712 } 713 714 715 void radius_client_update_acct_msgs(struct radius_client_data *radius, 716 u8 *shared_secret, 717 size_t shared_secret_len) 718 { 719 struct radius_msg_list *entry; 720 721 if (!radius) 722 return; 723 724 for (entry = radius->msgs; entry; entry = entry->next) { 725 if (entry->msg_type == RADIUS_ACCT) { 726 entry->shared_secret = shared_secret; 727 entry->shared_secret_len = shared_secret_len; 728 radius_msg_finish_acct(entry->msg, shared_secret, 729 shared_secret_len); 730 } 731 } 732 } 733 734 735 static int 736 radius_change_server(struct radius_client_data *radius, 737 struct hostapd_radius_server *nserv, 738 struct hostapd_radius_server *oserv, 739 int sock, int sock6, int auth) 740 { 741 struct sockaddr_in serv; 742 #ifdef CONFIG_IPV6 743 struct sockaddr_in6 serv6; 744 #endif /* CONFIG_IPV6 */ 745 struct sockaddr *addr; 746 socklen_t addrlen; 747 char abuf[50]; 748 int sel_sock; 749 struct radius_msg_list *entry; 750 751 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 752 HOSTAPD_LEVEL_INFO, 753 "%s server %s:%d", 754 auth ? "Authentication" : "Accounting", 755 hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), 756 nserv->port); 757 758 if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len || 759 os_memcmp(nserv->shared_secret, oserv->shared_secret, 760 nserv->shared_secret_len) != 0) { 761 /* Pending RADIUS packets used different shared secret, so 762 * they need to be modified. Update accounting message 763 * authenticators here. Authentication messages are removed 764 * since they would require more changes and the new RADIUS 765 * server may not be prepared to receive them anyway due to 766 * missing state information. Client will likely retry 767 * authentication, so this should not be an issue. */ 768 if (auth) 769 radius_client_flush(radius, 1); 770 else { 771 radius_client_update_acct_msgs( 772 radius, nserv->shared_secret, 773 nserv->shared_secret_len); 774 } 775 } 776 777 /* Reset retry counters for the new server */ 778 for (entry = radius->msgs; entry; entry = entry->next) { 779 if ((auth && entry->msg_type != RADIUS_AUTH) || 780 (!auth && entry->msg_type != RADIUS_ACCT)) 781 continue; 782 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; 783 entry->attempts = 0; 784 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; 785 } 786 787 if (radius->msgs) { 788 eloop_cancel_timeout(radius_client_timer, radius, NULL); 789 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, 790 radius_client_timer, radius, NULL); 791 } 792 793 switch (nserv->addr.af) { 794 case AF_INET: 795 os_memset(&serv, 0, sizeof(serv)); 796 serv.sin_family = AF_INET; 797 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr; 798 serv.sin_port = htons(nserv->port); 799 addr = (struct sockaddr *) &serv; 800 addrlen = sizeof(serv); 801 sel_sock = sock; 802 break; 803 #ifdef CONFIG_IPV6 804 case AF_INET6: 805 os_memset(&serv6, 0, sizeof(serv6)); 806 serv6.sin6_family = AF_INET6; 807 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6, 808 sizeof(struct in6_addr)); 809 serv6.sin6_port = htons(nserv->port); 810 addr = (struct sockaddr *) &serv6; 811 addrlen = sizeof(serv6); 812 sel_sock = sock6; 813 break; 814 #endif /* CONFIG_IPV6 */ 815 default: 816 return -1; 817 } 818 819 if (connect(sel_sock, addr, addrlen) < 0) { 820 perror("connect[radius]"); 821 return -1; 822 } 823 824 if (auth) 825 radius->auth_sock = sel_sock; 826 else 827 radius->acct_sock = sel_sock; 828 829 return 0; 830 } 831 832 833 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) 834 { 835 struct radius_client_data *radius = eloop_ctx; 836 struct hostapd_radius_servers *conf = radius->conf; 837 struct hostapd_radius_server *oserv; 838 839 if (radius->auth_sock >= 0 && conf->auth_servers && 840 conf->auth_server != conf->auth_servers) { 841 oserv = conf->auth_server; 842 conf->auth_server = conf->auth_servers; 843 radius_change_server(radius, conf->auth_server, oserv, 844 radius->auth_serv_sock, 845 radius->auth_serv_sock6, 1); 846 } 847 848 if (radius->acct_sock >= 0 && conf->acct_servers && 849 conf->acct_server != conf->acct_servers) { 850 oserv = conf->acct_server; 851 conf->acct_server = conf->acct_servers; 852 radius_change_server(radius, conf->acct_server, oserv, 853 radius->acct_serv_sock, 854 radius->acct_serv_sock6, 0); 855 } 856 857 if (conf->retry_primary_interval) 858 eloop_register_timeout(conf->retry_primary_interval, 0, 859 radius_retry_primary_timer, radius, 860 NULL); 861 } 862 863 864 static int radius_client_init_auth(struct radius_client_data *radius) 865 { 866 struct hostapd_radius_servers *conf = radius->conf; 867 int ok = 0; 868 869 radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); 870 if (radius->auth_serv_sock < 0) 871 perror("socket[PF_INET,SOCK_DGRAM]"); 872 else 873 ok++; 874 875 #ifdef CONFIG_IPV6 876 radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 877 if (radius->auth_serv_sock6 < 0) 878 perror("socket[PF_INET6,SOCK_DGRAM]"); 879 else 880 ok++; 881 #endif /* CONFIG_IPV6 */ 882 883 if (ok == 0) 884 return -1; 885 886 radius_change_server(radius, conf->auth_server, NULL, 887 radius->auth_serv_sock, radius->auth_serv_sock6, 888 1); 889 890 if (radius->auth_serv_sock >= 0 && 891 eloop_register_read_sock(radius->auth_serv_sock, 892 radius_client_receive, radius, 893 (void *) RADIUS_AUTH)) { 894 printf("Could not register read socket for authentication " 895 "server\n"); 896 return -1; 897 } 898 899 #ifdef CONFIG_IPV6 900 if (radius->auth_serv_sock6 >= 0 && 901 eloop_register_read_sock(radius->auth_serv_sock6, 902 radius_client_receive, radius, 903 (void *) RADIUS_AUTH)) { 904 printf("Could not register read socket for authentication " 905 "server\n"); 906 return -1; 907 } 908 #endif /* CONFIG_IPV6 */ 909 910 return 0; 911 } 912 913 914 static int radius_client_init_acct(struct radius_client_data *radius) 915 { 916 struct hostapd_radius_servers *conf = radius->conf; 917 int ok = 0; 918 919 radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); 920 if (radius->acct_serv_sock < 0) 921 perror("socket[PF_INET,SOCK_DGRAM]"); 922 else 923 ok++; 924 925 #ifdef CONFIG_IPV6 926 radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 927 if (radius->acct_serv_sock6 < 0) 928 perror("socket[PF_INET6,SOCK_DGRAM]"); 929 else 930 ok++; 931 #endif /* CONFIG_IPV6 */ 932 933 if (ok == 0) 934 return -1; 935 936 radius_change_server(radius, conf->acct_server, NULL, 937 radius->acct_serv_sock, radius->acct_serv_sock6, 938 0); 939 940 if (radius->acct_serv_sock >= 0 && 941 eloop_register_read_sock(radius->acct_serv_sock, 942 radius_client_receive, radius, 943 (void *) RADIUS_ACCT)) { 944 printf("Could not register read socket for accounting " 945 "server\n"); 946 return -1; 947 } 948 949 #ifdef CONFIG_IPV6 950 if (radius->acct_serv_sock6 >= 0 && 951 eloop_register_read_sock(radius->acct_serv_sock6, 952 radius_client_receive, radius, 953 (void *) RADIUS_ACCT)) { 954 printf("Could not register read socket for accounting " 955 "server\n"); 956 return -1; 957 } 958 #endif /* CONFIG_IPV6 */ 959 960 return 0; 961 } 962 963 964 struct radius_client_data * 965 radius_client_init(void *ctx, struct hostapd_radius_servers *conf) 966 { 967 struct radius_client_data *radius; 968 969 radius = wpa_zalloc(sizeof(struct radius_client_data)); 970 if (radius == NULL) 971 return NULL; 972 973 radius->ctx = ctx; 974 radius->conf = conf; 975 radius->auth_serv_sock = radius->acct_serv_sock = 976 radius->auth_serv_sock6 = radius->acct_serv_sock6 = 977 radius->auth_sock = radius->acct_sock = -1; 978 979 if (conf->auth_server && radius_client_init_auth(radius)) { 980 radius_client_deinit(radius); 981 return NULL; 982 } 983 984 if (conf->acct_server && radius_client_init_acct(radius)) { 985 radius_client_deinit(radius); 986 return NULL; 987 } 988 989 if (conf->retry_primary_interval) 990 eloop_register_timeout(conf->retry_primary_interval, 0, 991 radius_retry_primary_timer, radius, 992 NULL); 993 994 return radius; 995 } 996 997 998 void radius_client_deinit(struct radius_client_data *radius) 999 { 1000 if (!radius) 1001 return; 1002 1003 if (radius->auth_serv_sock >= 0) 1004 eloop_unregister_read_sock(radius->auth_serv_sock); 1005 if (radius->acct_serv_sock >= 0) 1006 eloop_unregister_read_sock(radius->acct_serv_sock); 1007 1008 eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL); 1009 1010 radius_client_flush(radius, 0); 1011 os_free(radius->auth_handlers); 1012 os_free(radius->acct_handlers); 1013 os_free(radius); 1014 } 1015 1016 1017 void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr) 1018 { 1019 struct radius_msg_list *entry, *prev, *tmp; 1020 1021 prev = NULL; 1022 entry = radius->msgs; 1023 while (entry) { 1024 if (entry->msg_type == RADIUS_AUTH && 1025 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { 1026 hostapd_logger(radius->ctx, addr, 1027 HOSTAPD_MODULE_RADIUS, 1028 HOSTAPD_LEVEL_DEBUG, 1029 "Removing pending RADIUS authentication" 1030 " message for removed client"); 1031 1032 if (prev) 1033 prev->next = entry->next; 1034 else 1035 radius->msgs = entry->next; 1036 1037 tmp = entry; 1038 entry = entry->next; 1039 radius_client_msg_free(tmp); 1040 radius->num_msgs--; 1041 continue; 1042 } 1043 1044 prev = entry; 1045 entry = entry->next; 1046 } 1047 } 1048 1049 1050 static int radius_client_dump_auth_server(char *buf, size_t buflen, 1051 struct hostapd_radius_server *serv, 1052 struct radius_client_data *cli) 1053 { 1054 int pending = 0; 1055 struct radius_msg_list *msg; 1056 char abuf[50]; 1057 1058 if (cli) { 1059 for (msg = cli->msgs; msg; msg = msg->next) { 1060 if (msg->msg_type == RADIUS_AUTH) 1061 pending++; 1062 } 1063 } 1064 1065 return os_snprintf(buf, buflen, 1066 "radiusAuthServerIndex=%d\n" 1067 "radiusAuthServerAddress=%s\n" 1068 "radiusAuthClientServerPortNumber=%d\n" 1069 "radiusAuthClientRoundTripTime=%d\n" 1070 "radiusAuthClientAccessRequests=%u\n" 1071 "radiusAuthClientAccessRetransmissions=%u\n" 1072 "radiusAuthClientAccessAccepts=%u\n" 1073 "radiusAuthClientAccessRejects=%u\n" 1074 "radiusAuthClientAccessChallenges=%u\n" 1075 "radiusAuthClientMalformedAccessResponses=%u\n" 1076 "radiusAuthClientBadAuthenticators=%u\n" 1077 "radiusAuthClientPendingRequests=%u\n" 1078 "radiusAuthClientTimeouts=%u\n" 1079 "radiusAuthClientUnknownTypes=%u\n" 1080 "radiusAuthClientPacketsDropped=%u\n", 1081 serv->index, 1082 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), 1083 serv->port, 1084 serv->round_trip_time, 1085 serv->requests, 1086 serv->retransmissions, 1087 serv->access_accepts, 1088 serv->access_rejects, 1089 serv->access_challenges, 1090 serv->malformed_responses, 1091 serv->bad_authenticators, 1092 pending, 1093 serv->timeouts, 1094 serv->unknown_types, 1095 serv->packets_dropped); 1096 } 1097 1098 1099 static int radius_client_dump_acct_server(char *buf, size_t buflen, 1100 struct hostapd_radius_server *serv, 1101 struct radius_client_data *cli) 1102 { 1103 int pending = 0; 1104 struct radius_msg_list *msg; 1105 char abuf[50]; 1106 1107 if (cli) { 1108 for (msg = cli->msgs; msg; msg = msg->next) { 1109 if (msg->msg_type == RADIUS_ACCT || 1110 msg->msg_type == RADIUS_ACCT_INTERIM) 1111 pending++; 1112 } 1113 } 1114 1115 return os_snprintf(buf, buflen, 1116 "radiusAccServerIndex=%d\n" 1117 "radiusAccServerAddress=%s\n" 1118 "radiusAccClientServerPortNumber=%d\n" 1119 "radiusAccClientRoundTripTime=%d\n" 1120 "radiusAccClientRequests=%u\n" 1121 "radiusAccClientRetransmissions=%u\n" 1122 "radiusAccClientResponses=%u\n" 1123 "radiusAccClientMalformedResponses=%u\n" 1124 "radiusAccClientBadAuthenticators=%u\n" 1125 "radiusAccClientPendingRequests=%u\n" 1126 "radiusAccClientTimeouts=%u\n" 1127 "radiusAccClientUnknownTypes=%u\n" 1128 "radiusAccClientPacketsDropped=%u\n", 1129 serv->index, 1130 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), 1131 serv->port, 1132 serv->round_trip_time, 1133 serv->requests, 1134 serv->retransmissions, 1135 serv->responses, 1136 serv->malformed_responses, 1137 serv->bad_authenticators, 1138 pending, 1139 serv->timeouts, 1140 serv->unknown_types, 1141 serv->packets_dropped); 1142 } 1143 1144 1145 int radius_client_get_mib(struct radius_client_data *radius, char *buf, 1146 size_t buflen) 1147 { 1148 struct hostapd_radius_servers *conf = radius->conf; 1149 int i; 1150 struct hostapd_radius_server *serv; 1151 int count = 0; 1152 1153 if (conf->auth_servers) { 1154 for (i = 0; i < conf->num_auth_servers; i++) { 1155 serv = &conf->auth_servers[i]; 1156 count += radius_client_dump_auth_server( 1157 buf + count, buflen - count, serv, 1158 serv == conf->auth_server ? 1159 radius : NULL); 1160 } 1161 } 1162 1163 if (conf->acct_servers) { 1164 for (i = 0; i < conf->num_acct_servers; i++) { 1165 serv = &conf->acct_servers[i]; 1166 count += radius_client_dump_acct_server( 1167 buf + count, buflen - count, serv, 1168 serv == conf->acct_server ? 1169 radius : NULL); 1170 } 1171 } 1172 1173 return count; 1174 } 1175 1176 1177 static int radius_servers_diff(struct hostapd_radius_server *nserv, 1178 struct hostapd_radius_server *oserv, 1179 int num) 1180 { 1181 int i; 1182 1183 for (i = 0; i < num; i++) { 1184 if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) || 1185 nserv[i].port != oserv[i].port || 1186 nserv[i].shared_secret_len != oserv[i].shared_secret_len || 1187 memcmp(nserv[i].shared_secret, oserv[i].shared_secret, 1188 nserv[i].shared_secret_len) != 0) 1189 return 1; 1190 } 1191 1192 return 0; 1193 } 1194 1195 1196 struct radius_client_data * 1197 radius_client_reconfig(struct radius_client_data *old, void *ctx, 1198 struct hostapd_radius_servers *oldconf, 1199 struct hostapd_radius_servers *newconf) 1200 { 1201 radius_client_flush(old, 0); 1202 1203 if (newconf->retry_primary_interval != 1204 oldconf->retry_primary_interval || 1205 newconf->num_auth_servers != oldconf->num_auth_servers || 1206 newconf->num_acct_servers != oldconf->num_acct_servers || 1207 radius_servers_diff(newconf->auth_servers, oldconf->auth_servers, 1208 newconf->num_auth_servers) || 1209 radius_servers_diff(newconf->acct_servers, oldconf->acct_servers, 1210 newconf->num_acct_servers)) { 1211 hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS, 1212 HOSTAPD_LEVEL_DEBUG, 1213 "Reconfiguring RADIUS client"); 1214 radius_client_deinit(old); 1215 return radius_client_init(ctx, newconf); 1216 } 1217 1218 return old; 1219 } 1220