$search
00001 /* 00002 * RADIUS client 00003 * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi> 00004 * 00005 * This program is free software; you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License version 2 as 00007 * published by the Free Software Foundation. 00008 * 00009 * Alternatively, this software may be distributed under the terms of BSD 00010 * license. 00011 * 00012 * See README and COPYING for more details. 00013 */ 00014 00015 #include "includes.h" 00016 00017 #include "common.h" 00018 #include "radius.h" 00019 #include "radius_client.h" 00020 #include "eloop.h" 00021 00022 /* Defaults for RADIUS retransmit values (exponential backoff) */ 00023 00027 #define RADIUS_CLIENT_FIRST_WAIT 3 00028 00032 #define RADIUS_CLIENT_MAX_WAIT 120 00033 00040 #define RADIUS_CLIENT_MAX_RETRIES 10 00041 00048 #define RADIUS_CLIENT_MAX_ENTRIES 30 00049 00056 #define RADIUS_CLIENT_NUM_FAILOVER 4 00057 00058 00067 struct radius_rx_handler { 00071 RadiusRxResult (*handler)(struct radius_msg *msg, 00072 struct radius_msg *req, 00073 const u8 *shared_secret, 00074 size_t shared_secret_len, 00075 void *data); 00076 00080 void *data; 00081 }; 00082 00083 00090 struct radius_msg_list { 00096 u8 addr[ETH_ALEN]; 00097 00101 struct radius_msg *msg; 00102 00106 RadiusType msg_type; 00107 00111 os_time_t first_try; 00112 00116 os_time_t next_try; 00117 00121 int attempts; 00122 00126 int next_wait; 00127 00131 struct os_time last_attempt; 00132 00136 const u8 *shared_secret; 00137 00141 size_t shared_secret_len; 00142 00143 /* TODO: server config with failover to backup server(s) */ 00144 00148 struct radius_msg_list *next; 00149 }; 00150 00151 00160 struct radius_client_data { 00164 void *ctx; 00165 00169 struct hostapd_radius_servers *conf; 00170 00174 int auth_serv_sock; 00175 00179 int acct_serv_sock; 00180 00184 int auth_serv_sock6; 00185 00189 int acct_serv_sock6; 00190 00194 int auth_sock; 00195 00199 int acct_sock; 00200 00204 struct radius_rx_handler *auth_handlers; 00205 00209 size_t num_auth_handlers; 00210 00214 struct radius_rx_handler *acct_handlers; 00215 00219 size_t num_acct_handlers; 00220 00224 struct radius_msg_list *msgs; 00225 00229 size_t num_msgs; 00230 00234 u8 next_radius_identifier; 00235 }; 00236 00237 00238 static int 00239 radius_change_server(struct radius_client_data *radius, 00240 struct hostapd_radius_server *nserv, 00241 struct hostapd_radius_server *oserv, 00242 int sock, int sock6, int auth); 00243 static int radius_client_init_acct(struct radius_client_data *radius); 00244 static int radius_client_init_auth(struct radius_client_data *radius); 00245 00246 00247 static void radius_client_msg_free(struct radius_msg_list *req) 00248 { 00249 radius_msg_free(req->msg); 00250 os_free(req); 00251 } 00252 00253 00270 int radius_client_register(struct radius_client_data *radius, 00271 RadiusType msg_type, 00272 RadiusRxResult (*handler)(struct radius_msg *msg, 00273 struct radius_msg *req, 00274 const u8 *shared_secret, 00275 size_t shared_secret_len, 00276 void *data), 00277 void *data) 00278 { 00279 struct radius_rx_handler **handlers, *newh; 00280 size_t *num; 00281 00282 if (msg_type == RADIUS_ACCT) { 00283 handlers = &radius->acct_handlers; 00284 num = &radius->num_acct_handlers; 00285 } else { 00286 handlers = &radius->auth_handlers; 00287 num = &radius->num_auth_handlers; 00288 } 00289 00290 newh = os_realloc(*handlers, 00291 (*num + 1) * sizeof(struct radius_rx_handler)); 00292 if (newh == NULL) 00293 return -1; 00294 00295 newh[*num].handler = handler; 00296 newh[*num].data = data; 00297 (*num)++; 00298 *handlers = newh; 00299 00300 return 0; 00301 } 00302 00303 00304 static void radius_client_handle_send_error(struct radius_client_data *radius, 00305 int s, RadiusType msg_type) 00306 { 00307 #ifndef CONFIG_NATIVE_WINDOWS 00308 int _errno = errno; 00309 perror("send[RADIUS]"); 00310 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL || 00311 _errno == EBADF) { 00312 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00313 HOSTAPD_LEVEL_INFO, 00314 "Send failed - maybe interface status changed -" 00315 " try to connect again"); 00316 eloop_unregister_read_sock(s); 00317 close(s); 00318 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) 00319 radius_client_init_acct(radius); 00320 else 00321 radius_client_init_auth(radius); 00322 } 00323 #endif /* CONFIG_NATIVE_WINDOWS */ 00324 } 00325 00326 00327 static int radius_client_retransmit(struct radius_client_data *radius, 00328 struct radius_msg_list *entry, 00329 os_time_t now) 00330 { 00331 struct hostapd_radius_servers *conf = radius->conf; 00332 int s; 00333 struct wpabuf *buf; 00334 00335 if (entry->msg_type == RADIUS_ACCT || 00336 entry->msg_type == RADIUS_ACCT_INTERIM) { 00337 s = radius->acct_sock; 00338 if (entry->attempts == 0) 00339 conf->acct_server->requests++; 00340 else { 00341 conf->acct_server->timeouts++; 00342 conf->acct_server->retransmissions++; 00343 } 00344 } else { 00345 s = radius->auth_sock; 00346 if (entry->attempts == 0) 00347 conf->auth_server->requests++; 00348 else { 00349 conf->auth_server->timeouts++; 00350 conf->auth_server->retransmissions++; 00351 } 00352 } 00353 00354 /* retransmit; remove entry if too many attempts */ 00355 entry->attempts++; 00356 hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS, 00357 HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)", 00358 radius_msg_get_hdr(entry->msg)->identifier); 00359 00360 os_get_time(&entry->last_attempt); 00361 buf = radius_msg_get_buf(entry->msg); 00362 if (send(s, wpabuf_head(buf), wpabuf_len(buf), 0) < 0) 00363 radius_client_handle_send_error(radius, s, entry->msg_type); 00364 00365 entry->next_try = now + entry->next_wait; 00366 entry->next_wait *= 2; 00367 if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT) 00368 entry->next_wait = RADIUS_CLIENT_MAX_WAIT; 00369 if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) { 00370 printf("Removing un-ACKed RADIUS message due to too many " 00371 "failed retransmit attempts\n"); 00372 return 1; 00373 } 00374 00375 return 0; 00376 } 00377 00378 00379 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx) 00380 { 00381 struct radius_client_data *radius = eloop_ctx; 00382 struct hostapd_radius_servers *conf = radius->conf; 00383 struct os_time now; 00384 os_time_t first; 00385 struct radius_msg_list *entry, *prev, *tmp; 00386 int auth_failover = 0, acct_failover = 0; 00387 char abuf[50]; 00388 00389 entry = radius->msgs; 00390 if (!entry) 00391 return; 00392 00393 os_get_time(&now); 00394 first = 0; 00395 00396 prev = NULL; 00397 while (entry) { 00398 if (now.sec >= entry->next_try && 00399 radius_client_retransmit(radius, entry, now.sec)) { 00400 if (prev) 00401 prev->next = entry->next; 00402 else 00403 radius->msgs = entry->next; 00404 00405 tmp = entry; 00406 entry = entry->next; 00407 radius_client_msg_free(tmp); 00408 radius->num_msgs--; 00409 continue; 00410 } 00411 00412 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) { 00413 if (entry->msg_type == RADIUS_ACCT || 00414 entry->msg_type == RADIUS_ACCT_INTERIM) 00415 acct_failover++; 00416 else 00417 auth_failover++; 00418 } 00419 00420 if (first == 0 || entry->next_try < first) 00421 first = entry->next_try; 00422 00423 prev = entry; 00424 entry = entry->next; 00425 } 00426 00427 if (radius->msgs) { 00428 if (first < now.sec) 00429 first = now.sec; 00430 eloop_register_timeout(first - now.sec, 0, 00431 radius_client_timer, radius, NULL); 00432 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00433 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client " 00434 "retransmit in %ld seconds", 00435 (long int) (first - now.sec)); 00436 } 00437 00438 if (auth_failover && conf->num_auth_servers > 1) { 00439 struct hostapd_radius_server *next, *old; 00440 old = conf->auth_server; 00441 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00442 HOSTAPD_LEVEL_NOTICE, 00443 "No response from Authentication server " 00444 "%s:%d - failover", 00445 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), 00446 old->port); 00447 00448 for (entry = radius->msgs; entry; entry = entry->next) { 00449 if (entry->msg_type == RADIUS_AUTH) 00450 old->timeouts++; 00451 } 00452 00453 next = old + 1; 00454 if (next > &(conf->auth_servers[conf->num_auth_servers - 1])) 00455 next = conf->auth_servers; 00456 conf->auth_server = next; 00457 radius_change_server(radius, next, old, 00458 radius->auth_serv_sock, 00459 radius->auth_serv_sock6, 1); 00460 } 00461 00462 if (acct_failover && conf->num_acct_servers > 1) { 00463 struct hostapd_radius_server *next, *old; 00464 old = conf->acct_server; 00465 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00466 HOSTAPD_LEVEL_NOTICE, 00467 "No response from Accounting server " 00468 "%s:%d - failover", 00469 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)), 00470 old->port); 00471 00472 for (entry = radius->msgs; entry; entry = entry->next) { 00473 if (entry->msg_type == RADIUS_ACCT || 00474 entry->msg_type == RADIUS_ACCT_INTERIM) 00475 old->timeouts++; 00476 } 00477 00478 next = old + 1; 00479 if (next > &conf->acct_servers[conf->num_acct_servers - 1]) 00480 next = conf->acct_servers; 00481 conf->acct_server = next; 00482 radius_change_server(radius, next, old, 00483 radius->acct_serv_sock, 00484 radius->acct_serv_sock6, 0); 00485 } 00486 } 00487 00488 00489 static void radius_client_update_timeout(struct radius_client_data *radius) 00490 { 00491 struct os_time now; 00492 os_time_t first; 00493 struct radius_msg_list *entry; 00494 00495 eloop_cancel_timeout(radius_client_timer, radius, NULL); 00496 00497 if (radius->msgs == NULL) { 00498 return; 00499 } 00500 00501 first = 0; 00502 for (entry = radius->msgs; entry; entry = entry->next) { 00503 if (first == 0 || entry->next_try < first) 00504 first = entry->next_try; 00505 } 00506 00507 os_get_time(&now); 00508 if (first < now.sec) 00509 first = now.sec; 00510 eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius, 00511 NULL); 00512 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00513 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in" 00514 " %ld seconds\n", (long int) (first - now.sec)); 00515 } 00516 00517 00518 static void radius_client_list_add(struct radius_client_data *radius, 00519 struct radius_msg *msg, 00520 RadiusType msg_type, 00521 const u8 *shared_secret, 00522 size_t shared_secret_len, const u8 *addr) 00523 { 00524 struct radius_msg_list *entry, *prev; 00525 00526 if (eloop_terminated()) { 00527 /* No point in adding entries to retransmit queue since event 00528 * loop has already been terminated. */ 00529 radius_msg_free(msg); 00530 return; 00531 } 00532 00533 entry = os_zalloc(sizeof(*entry)); 00534 if (entry == NULL) { 00535 printf("Failed to add RADIUS packet into retransmit list\n"); 00536 radius_msg_free(msg); 00537 return; 00538 } 00539 00540 if (addr) 00541 os_memcpy(entry->addr, addr, ETH_ALEN); 00542 entry->msg = msg; 00543 entry->msg_type = msg_type; 00544 entry->shared_secret = shared_secret; 00545 entry->shared_secret_len = shared_secret_len; 00546 os_get_time(&entry->last_attempt); 00547 entry->first_try = entry->last_attempt.sec; 00548 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; 00549 entry->attempts = 1; 00550 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; 00551 entry->next = radius->msgs; 00552 radius->msgs = entry; 00553 radius_client_update_timeout(radius); 00554 00555 if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) { 00556 printf("Removing the oldest un-ACKed RADIUS packet due to " 00557 "retransmit list limits.\n"); 00558 prev = NULL; 00559 while (entry->next) { 00560 prev = entry; 00561 entry = entry->next; 00562 } 00563 if (prev) { 00564 prev->next = NULL; 00565 radius_client_msg_free(entry); 00566 } 00567 } else 00568 radius->num_msgs++; 00569 } 00570 00571 00572 static void radius_client_list_del(struct radius_client_data *radius, 00573 RadiusType msg_type, const u8 *addr) 00574 { 00575 struct radius_msg_list *entry, *prev, *tmp; 00576 00577 if (addr == NULL) 00578 return; 00579 00580 entry = radius->msgs; 00581 prev = NULL; 00582 while (entry) { 00583 if (entry->msg_type == msg_type && 00584 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { 00585 if (prev) 00586 prev->next = entry->next; 00587 else 00588 radius->msgs = entry->next; 00589 tmp = entry; 00590 entry = entry->next; 00591 hostapd_logger(radius->ctx, addr, 00592 HOSTAPD_MODULE_RADIUS, 00593 HOSTAPD_LEVEL_DEBUG, 00594 "Removing matching RADIUS message"); 00595 radius_client_msg_free(tmp); 00596 radius->num_msgs--; 00597 continue; 00598 } 00599 prev = entry; 00600 entry = entry->next; 00601 } 00602 } 00603 00604 00627 int radius_client_send(struct radius_client_data *radius, 00628 struct radius_msg *msg, RadiusType msg_type, 00629 const u8 *addr) 00630 { 00631 struct hostapd_radius_servers *conf = radius->conf; 00632 const u8 *shared_secret; 00633 size_t shared_secret_len; 00634 char *name; 00635 int s, res; 00636 struct wpabuf *buf; 00637 00638 if (msg_type == RADIUS_ACCT_INTERIM) { 00639 /* Remove any pending interim acct update for the same STA. */ 00640 radius_client_list_del(radius, msg_type, addr); 00641 } 00642 00643 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) { 00644 if (conf->acct_server == NULL) { 00645 hostapd_logger(radius->ctx, NULL, 00646 HOSTAPD_MODULE_RADIUS, 00647 HOSTAPD_LEVEL_INFO, 00648 "No accounting server configured"); 00649 return -1; 00650 } 00651 shared_secret = conf->acct_server->shared_secret; 00652 shared_secret_len = conf->acct_server->shared_secret_len; 00653 radius_msg_finish_acct(msg, shared_secret, shared_secret_len); 00654 name = "accounting"; 00655 s = radius->acct_sock; 00656 conf->acct_server->requests++; 00657 } else { 00658 if (conf->auth_server == NULL) { 00659 hostapd_logger(radius->ctx, NULL, 00660 HOSTAPD_MODULE_RADIUS, 00661 HOSTAPD_LEVEL_INFO, 00662 "No authentication server configured"); 00663 return -1; 00664 } 00665 shared_secret = conf->auth_server->shared_secret; 00666 shared_secret_len = conf->auth_server->shared_secret_len; 00667 radius_msg_finish(msg, shared_secret, shared_secret_len); 00668 name = "authentication"; 00669 s = radius->auth_sock; 00670 conf->auth_server->requests++; 00671 } 00672 00673 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00674 HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s " 00675 "server", name); 00676 if (conf->msg_dumps) 00677 radius_msg_dump(msg); 00678 00679 buf = radius_msg_get_buf(msg); 00680 res = send(s, wpabuf_head(buf), wpabuf_len(buf), 0); 00681 if (res < 0) 00682 radius_client_handle_send_error(radius, s, msg_type); 00683 00684 radius_client_list_add(radius, msg, msg_type, shared_secret, 00685 shared_secret_len, addr); 00686 00687 return res; 00688 } 00689 00690 00691 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx) 00692 { 00693 struct radius_client_data *radius = eloop_ctx; 00694 struct hostapd_radius_servers *conf = radius->conf; 00695 RadiusType msg_type = (RadiusType) sock_ctx; 00696 int len, roundtrip; 00697 unsigned char buf[3000]; 00698 struct radius_msg *msg; 00699 struct radius_hdr *hdr; 00700 struct radius_rx_handler *handlers; 00701 size_t num_handlers, i; 00702 struct radius_msg_list *req, *prev_req; 00703 struct os_time now; 00704 struct hostapd_radius_server *rconf; 00705 int invalid_authenticator = 0; 00706 00707 if (msg_type == RADIUS_ACCT) { 00708 handlers = radius->acct_handlers; 00709 num_handlers = radius->num_acct_handlers; 00710 rconf = conf->acct_server; 00711 } else { 00712 handlers = radius->auth_handlers; 00713 num_handlers = radius->num_auth_handlers; 00714 rconf = conf->auth_server; 00715 } 00716 00717 len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT); 00718 if (len < 0) { 00719 perror("recv[RADIUS]"); 00720 return; 00721 } 00722 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00723 HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS " 00724 "server", len); 00725 if (len == sizeof(buf)) { 00726 printf("Possibly too long UDP frame for our buffer - " 00727 "dropping it\n"); 00728 return; 00729 } 00730 00731 msg = radius_msg_parse(buf, len); 00732 if (msg == NULL) { 00733 printf("Parsing incoming RADIUS frame failed\n"); 00734 rconf->malformed_responses++; 00735 return; 00736 } 00737 hdr = radius_msg_get_hdr(msg); 00738 00739 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00740 HOSTAPD_LEVEL_DEBUG, "Received RADIUS message"); 00741 if (conf->msg_dumps) 00742 radius_msg_dump(msg); 00743 00744 switch (hdr->code) { 00745 case RADIUS_CODE_ACCESS_ACCEPT: 00746 rconf->access_accepts++; 00747 break; 00748 case RADIUS_CODE_ACCESS_REJECT: 00749 rconf->access_rejects++; 00750 break; 00751 case RADIUS_CODE_ACCESS_CHALLENGE: 00752 rconf->access_challenges++; 00753 break; 00754 case RADIUS_CODE_ACCOUNTING_RESPONSE: 00755 rconf->responses++; 00756 break; 00757 } 00758 00759 prev_req = NULL; 00760 req = radius->msgs; 00761 while (req) { 00762 /* TODO: also match by src addr:port of the packet when using 00763 * alternative RADIUS servers (?) */ 00764 if ((req->msg_type == msg_type || 00765 (req->msg_type == RADIUS_ACCT_INTERIM && 00766 msg_type == RADIUS_ACCT)) && 00767 radius_msg_get_hdr(req->msg)->identifier == 00768 hdr->identifier) 00769 break; 00770 00771 prev_req = req; 00772 req = req->next; 00773 } 00774 00775 if (req == NULL) { 00776 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00777 HOSTAPD_LEVEL_DEBUG, 00778 "No matching RADIUS request found (type=%d " 00779 "id=%d) - dropping packet", 00780 msg_type, hdr->identifier); 00781 goto fail; 00782 } 00783 00784 os_get_time(&now); 00785 roundtrip = (now.sec - req->last_attempt.sec) * 100 + 00786 (now.usec - req->last_attempt.usec) / 10000; 00787 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, 00788 HOSTAPD_LEVEL_DEBUG, 00789 "Received RADIUS packet matched with a pending " 00790 "request, round trip time %d.%02d sec", 00791 roundtrip / 100, roundtrip % 100); 00792 rconf->round_trip_time = roundtrip; 00793 00794 /* Remove ACKed RADIUS packet from retransmit list */ 00795 if (prev_req) 00796 prev_req->next = req->next; 00797 else 00798 radius->msgs = req->next; 00799 radius->num_msgs--; 00800 00801 for (i = 0; i < num_handlers; i++) { 00802 RadiusRxResult res; 00803 res = handlers[i].handler(msg, req->msg, req->shared_secret, 00804 req->shared_secret_len, 00805 handlers[i].data); 00806 switch (res) { 00807 case RADIUS_RX_PROCESSED: 00808 radius_msg_free(msg); 00809 /* continue */ 00810 case RADIUS_RX_QUEUED: 00811 radius_client_msg_free(req); 00812 return; 00813 case RADIUS_RX_INVALID_AUTHENTICATOR: 00814 invalid_authenticator++; 00815 /* continue */ 00816 case RADIUS_RX_UNKNOWN: 00817 /* continue with next handler */ 00818 break; 00819 } 00820 } 00821 00822 if (invalid_authenticator) 00823 rconf->bad_authenticators++; 00824 else 00825 rconf->unknown_types++; 00826 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS, 00827 HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found " 00828 "(type=%d code=%d id=%d)%s - dropping packet", 00829 msg_type, hdr->code, hdr->identifier, 00830 invalid_authenticator ? " [INVALID AUTHENTICATOR]" : 00831 ""); 00832 radius_client_msg_free(req); 00833 00834 fail: 00835 radius_msg_free(msg); 00836 } 00837 00838 00847 u8 radius_client_get_id(struct radius_client_data *radius) 00848 { 00849 struct radius_msg_list *entry, *prev, *_remove; 00850 u8 id = radius->next_radius_identifier++; 00851 00852 /* remove entries with matching id from retransmit list to avoid 00853 * using new reply from the RADIUS server with an old request */ 00854 entry = radius->msgs; 00855 prev = NULL; 00856 while (entry) { 00857 if (radius_msg_get_hdr(entry->msg)->identifier == id) { 00858 hostapd_logger(radius->ctx, entry->addr, 00859 HOSTAPD_MODULE_RADIUS, 00860 HOSTAPD_LEVEL_DEBUG, 00861 "Removing pending RADIUS message, " 00862 "since its id (%d) is reused", id); 00863 if (prev) 00864 prev->next = entry->next; 00865 else 00866 radius->msgs = entry->next; 00867 _remove = entry; 00868 } else { 00869 _remove = NULL; 00870 prev = entry; 00871 } 00872 entry = entry->next; 00873 00874 if (_remove) 00875 radius_client_msg_free(_remove); 00876 } 00877 00878 return id; 00879 } 00880 00881 00887 void radius_client_flush(struct radius_client_data *radius, int only_auth) 00888 { 00889 struct radius_msg_list *entry, *prev, *tmp; 00890 00891 if (!radius) 00892 return; 00893 00894 prev = NULL; 00895 entry = radius->msgs; 00896 00897 while (entry) { 00898 if (!only_auth || entry->msg_type == RADIUS_AUTH) { 00899 if (prev) 00900 prev->next = entry->next; 00901 else 00902 radius->msgs = entry->next; 00903 00904 tmp = entry; 00905 entry = entry->next; 00906 radius_client_msg_free(tmp); 00907 radius->num_msgs--; 00908 } else { 00909 prev = entry; 00910 entry = entry->next; 00911 } 00912 } 00913 00914 if (radius->msgs == NULL) 00915 eloop_cancel_timeout(radius_client_timer, radius, NULL); 00916 } 00917 00918 00919 static void radius_client_update_acct_msgs(struct radius_client_data *radius, 00920 const u8 *shared_secret, 00921 size_t shared_secret_len) 00922 { 00923 struct radius_msg_list *entry; 00924 00925 if (!radius) 00926 return; 00927 00928 for (entry = radius->msgs; entry; entry = entry->next) { 00929 if (entry->msg_type == RADIUS_ACCT) { 00930 entry->shared_secret = shared_secret; 00931 entry->shared_secret_len = shared_secret_len; 00932 radius_msg_finish_acct(entry->msg, shared_secret, 00933 shared_secret_len); 00934 } 00935 } 00936 } 00937 00938 00939 static int 00940 radius_change_server(struct radius_client_data *radius, 00941 struct hostapd_radius_server *nserv, 00942 struct hostapd_radius_server *oserv, 00943 int sock, int sock6, int auth) 00944 { 00945 struct sockaddr_in serv, claddr; 00946 #ifdef CONFIG_IPV6 00947 struct sockaddr_in6 serv6, claddr6; 00948 #endif /* CONFIG_IPV6 */ 00949 struct sockaddr *addr, *cl_addr; 00950 socklen_t addrlen, claddrlen; 00951 char abuf[50]; 00952 int sel_sock; 00953 struct radius_msg_list *entry; 00954 struct hostapd_radius_servers *conf = radius->conf; 00955 00956 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS, 00957 HOSTAPD_LEVEL_INFO, 00958 "%s server %s:%d", 00959 auth ? "Authentication" : "Accounting", 00960 hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)), 00961 nserv->port); 00962 00963 if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len || 00964 os_memcmp(nserv->shared_secret, oserv->shared_secret, 00965 nserv->shared_secret_len) != 0) { 00966 /* Pending RADIUS packets used different shared secret, so 00967 * they need to be modified. Update accounting message 00968 * authenticators here. Authentication messages are removed 00969 * since they would require more changes and the new RADIUS 00970 * server may not be prepared to receive them anyway due to 00971 * missing state information. Client will likely retry 00972 * authentication, so this should not be an issue. */ 00973 if (auth) 00974 radius_client_flush(radius, 1); 00975 else { 00976 radius_client_update_acct_msgs( 00977 radius, nserv->shared_secret, 00978 nserv->shared_secret_len); 00979 } 00980 } 00981 00982 /* Reset retry counters for the new server */ 00983 for (entry = radius->msgs; entry; entry = entry->next) { 00984 if ((auth && entry->msg_type != RADIUS_AUTH) || 00985 (!auth && entry->msg_type != RADIUS_ACCT)) 00986 continue; 00987 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT; 00988 entry->attempts = 0; 00989 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2; 00990 } 00991 00992 if (radius->msgs) { 00993 eloop_cancel_timeout(radius_client_timer, radius, NULL); 00994 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, 00995 radius_client_timer, radius, NULL); 00996 } 00997 00998 switch (nserv->addr.af) { 00999 case AF_INET: 01000 os_memset(&serv, 0, sizeof(serv)); 01001 serv.sin_family = AF_INET; 01002 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr; 01003 serv.sin_port = htons(nserv->port); 01004 addr = (struct sockaddr *) &serv; 01005 addrlen = sizeof(serv); 01006 sel_sock = sock; 01007 break; 01008 #ifdef CONFIG_IPV6 01009 case AF_INET6: 01010 os_memset(&serv6, 0, sizeof(serv6)); 01011 serv6.sin6_family = AF_INET6; 01012 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6, 01013 sizeof(struct in6_addr)); 01014 serv6.sin6_port = htons(nserv->port); 01015 addr = (struct sockaddr *) &serv6; 01016 addrlen = sizeof(serv6); 01017 sel_sock = sock6; 01018 break; 01019 #endif /* CONFIG_IPV6 */ 01020 default: 01021 return -1; 01022 } 01023 01024 if (conf->force_client_addr) { 01025 switch (conf->client_addr.af) { 01026 case AF_INET: 01027 os_memset(&claddr, 0, sizeof(claddr)); 01028 claddr.sin_family = AF_INET; 01029 claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr; 01030 claddr.sin_port = htons(0); 01031 cl_addr = (struct sockaddr *) &claddr; 01032 claddrlen = sizeof(claddr); 01033 break; 01034 #ifdef CONFIG_IPV6 01035 case AF_INET6: 01036 os_memset(&claddr6, 0, sizeof(claddr6)); 01037 claddr6.sin6_family = AF_INET6; 01038 os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6, 01039 sizeof(struct in6_addr)); 01040 claddr6.sin6_port = htons(0); 01041 cl_addr = (struct sockaddr *) &claddr6; 01042 claddrlen = sizeof(claddr6); 01043 break; 01044 #endif /* CONFIG_IPV6 */ 01045 default: 01046 return -1; 01047 } 01048 01049 if (bind(sel_sock, cl_addr, claddrlen) < 0) { 01050 perror("bind[radius]"); 01051 return -1; 01052 } 01053 } 01054 01055 if (connect(sel_sock, addr, addrlen) < 0) { 01056 perror("connect[radius]"); 01057 return -1; 01058 } 01059 01060 #ifndef CONFIG_NATIVE_WINDOWS 01061 switch (nserv->addr.af) { 01062 case AF_INET: 01063 claddrlen = sizeof(claddr); 01064 getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen); 01065 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", 01066 inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port)); 01067 break; 01068 #ifdef CONFIG_IPV6 01069 case AF_INET6: { 01070 claddrlen = sizeof(claddr6); 01071 getsockname(sel_sock, (struct sockaddr *) &claddr6, 01072 &claddrlen); 01073 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u", 01074 inet_ntop(AF_INET6, &claddr6.sin6_addr, 01075 abuf, sizeof(abuf)), 01076 ntohs(claddr6.sin6_port)); 01077 break; 01078 } 01079 #endif /* CONFIG_IPV6 */ 01080 } 01081 #endif /* CONFIG_NATIVE_WINDOWS */ 01082 01083 if (auth) 01084 radius->auth_sock = sel_sock; 01085 else 01086 radius->acct_sock = sel_sock; 01087 01088 return 0; 01089 } 01090 01091 01092 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx) 01093 { 01094 struct radius_client_data *radius = eloop_ctx; 01095 struct hostapd_radius_servers *conf = radius->conf; 01096 struct hostapd_radius_server *oserv; 01097 01098 if (radius->auth_sock >= 0 && conf->auth_servers && 01099 conf->auth_server != conf->auth_servers) { 01100 oserv = conf->auth_server; 01101 conf->auth_server = conf->auth_servers; 01102 radius_change_server(radius, conf->auth_server, oserv, 01103 radius->auth_serv_sock, 01104 radius->auth_serv_sock6, 1); 01105 } 01106 01107 if (radius->acct_sock >= 0 && conf->acct_servers && 01108 conf->acct_server != conf->acct_servers) { 01109 oserv = conf->acct_server; 01110 conf->acct_server = conf->acct_servers; 01111 radius_change_server(radius, conf->acct_server, oserv, 01112 radius->acct_serv_sock, 01113 radius->acct_serv_sock6, 0); 01114 } 01115 01116 if (conf->retry_primary_interval) 01117 eloop_register_timeout(conf->retry_primary_interval, 0, 01118 radius_retry_primary_timer, radius, 01119 NULL); 01120 } 01121 01122 01123 static int radius_client_disable_pmtu_discovery(int s) 01124 { 01125 int r = -1; 01126 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT) 01127 /* Turn off Path MTU discovery on IPv4/UDP sockets. */ 01128 int action = IP_PMTUDISC_DONT; 01129 r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action, 01130 sizeof(action)); 01131 if (r == -1) 01132 wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: " 01133 "%s", strerror(errno)); 01134 #endif 01135 return r; 01136 } 01137 01138 01139 static int radius_client_init_auth(struct radius_client_data *radius) 01140 { 01141 struct hostapd_radius_servers *conf = radius->conf; 01142 int ok = 0; 01143 01144 radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); 01145 if (radius->auth_serv_sock < 0) 01146 perror("socket[PF_INET,SOCK_DGRAM]"); 01147 else { 01148 radius_client_disable_pmtu_discovery(radius->auth_serv_sock); 01149 ok++; 01150 } 01151 01152 #ifdef CONFIG_IPV6 01153 radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 01154 if (radius->auth_serv_sock6 < 0) 01155 perror("socket[PF_INET6,SOCK_DGRAM]"); 01156 else 01157 ok++; 01158 #endif /* CONFIG_IPV6 */ 01159 01160 if (ok == 0) 01161 return -1; 01162 01163 radius_change_server(radius, conf->auth_server, NULL, 01164 radius->auth_serv_sock, radius->auth_serv_sock6, 01165 1); 01166 01167 if (radius->auth_serv_sock >= 0 && 01168 eloop_register_read_sock(radius->auth_serv_sock, 01169 radius_client_receive, radius, 01170 (void *) RADIUS_AUTH)) { 01171 printf("Could not register read socket for authentication " 01172 "server\n"); 01173 return -1; 01174 } 01175 01176 #ifdef CONFIG_IPV6 01177 if (radius->auth_serv_sock6 >= 0 && 01178 eloop_register_read_sock(radius->auth_serv_sock6, 01179 radius_client_receive, radius, 01180 (void *) RADIUS_AUTH)) { 01181 printf("Could not register read socket for authentication " 01182 "server\n"); 01183 return -1; 01184 } 01185 #endif /* CONFIG_IPV6 */ 01186 01187 return 0; 01188 } 01189 01190 01191 static int radius_client_init_acct(struct radius_client_data *radius) 01192 { 01193 struct hostapd_radius_servers *conf = radius->conf; 01194 int ok = 0; 01195 01196 radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0); 01197 if (radius->acct_serv_sock < 0) 01198 perror("socket[PF_INET,SOCK_DGRAM]"); 01199 else { 01200 radius_client_disable_pmtu_discovery(radius->acct_serv_sock); 01201 ok++; 01202 } 01203 01204 #ifdef CONFIG_IPV6 01205 radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0); 01206 if (radius->acct_serv_sock6 < 0) 01207 perror("socket[PF_INET6,SOCK_DGRAM]"); 01208 else 01209 ok++; 01210 #endif /* CONFIG_IPV6 */ 01211 01212 if (ok == 0) 01213 return -1; 01214 01215 radius_change_server(radius, conf->acct_server, NULL, 01216 radius->acct_serv_sock, radius->acct_serv_sock6, 01217 0); 01218 01219 if (radius->acct_serv_sock >= 0 && 01220 eloop_register_read_sock(radius->acct_serv_sock, 01221 radius_client_receive, radius, 01222 (void *) RADIUS_ACCT)) { 01223 printf("Could not register read socket for accounting " 01224 "server\n"); 01225 return -1; 01226 } 01227 01228 #ifdef CONFIG_IPV6 01229 if (radius->acct_serv_sock6 >= 0 && 01230 eloop_register_read_sock(radius->acct_serv_sock6, 01231 radius_client_receive, radius, 01232 (void *) RADIUS_ACCT)) { 01233 printf("Could not register read socket for accounting " 01234 "server\n"); 01235 return -1; 01236 } 01237 #endif /* CONFIG_IPV6 */ 01238 01239 return 0; 01240 } 01241 01242 01253 struct radius_client_data * 01254 radius_client_init(void *ctx, struct hostapd_radius_servers *conf) 01255 { 01256 struct radius_client_data *radius; 01257 01258 radius = os_zalloc(sizeof(struct radius_client_data)); 01259 if (radius == NULL) 01260 return NULL; 01261 01262 radius->ctx = ctx; 01263 radius->conf = conf; 01264 radius->auth_serv_sock = radius->acct_serv_sock = 01265 radius->auth_serv_sock6 = radius->acct_serv_sock6 = 01266 radius->auth_sock = radius->acct_sock = -1; 01267 01268 if (conf->auth_server && radius_client_init_auth(radius)) { 01269 radius_client_deinit(radius); 01270 return NULL; 01271 } 01272 01273 if (conf->acct_server && radius_client_init_acct(radius)) { 01274 radius_client_deinit(radius); 01275 return NULL; 01276 } 01277 01278 if (conf->retry_primary_interval) 01279 eloop_register_timeout(conf->retry_primary_interval, 0, 01280 radius_retry_primary_timer, radius, 01281 NULL); 01282 01283 return radius; 01284 } 01285 01286 01291 void radius_client_deinit(struct radius_client_data *radius) 01292 { 01293 if (!radius) 01294 return; 01295 01296 if (radius->auth_serv_sock >= 0) 01297 eloop_unregister_read_sock(radius->auth_serv_sock); 01298 if (radius->acct_serv_sock >= 0) 01299 eloop_unregister_read_sock(radius->acct_serv_sock); 01300 #ifdef CONFIG_IPV6 01301 if (radius->auth_serv_sock6 >= 0) 01302 eloop_unregister_read_sock(radius->auth_serv_sock6); 01303 if (radius->acct_serv_sock6 >= 0) 01304 eloop_unregister_read_sock(radius->acct_serv_sock6); 01305 #endif /* CONFIG_IPV6 */ 01306 01307 eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL); 01308 01309 radius_client_flush(radius, 0); 01310 os_free(radius->auth_handlers); 01311 os_free(radius->acct_handlers); 01312 os_free(radius); 01313 } 01314 01315 01326 void radius_client_flush_auth(struct radius_client_data *radius, 01327 const u8 *addr) 01328 { 01329 struct radius_msg_list *entry, *prev, *tmp; 01330 01331 prev = NULL; 01332 entry = radius->msgs; 01333 while (entry) { 01334 if (entry->msg_type == RADIUS_AUTH && 01335 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) { 01336 hostapd_logger(radius->ctx, addr, 01337 HOSTAPD_MODULE_RADIUS, 01338 HOSTAPD_LEVEL_DEBUG, 01339 "Removing pending RADIUS authentication" 01340 " message for removed client"); 01341 01342 if (prev) 01343 prev->next = entry->next; 01344 else 01345 radius->msgs = entry->next; 01346 01347 tmp = entry; 01348 entry = entry->next; 01349 radius_client_msg_free(tmp); 01350 radius->num_msgs--; 01351 continue; 01352 } 01353 01354 prev = entry; 01355 entry = entry->next; 01356 } 01357 } 01358 01359 01360 static int radius_client_dump_auth_server(char *buf, size_t buflen, 01361 struct hostapd_radius_server *serv, 01362 struct radius_client_data *cli) 01363 { 01364 int pending = 0; 01365 struct radius_msg_list *msg; 01366 char abuf[50]; 01367 01368 if (cli) { 01369 for (msg = cli->msgs; msg; msg = msg->next) { 01370 if (msg->msg_type == RADIUS_AUTH) 01371 pending++; 01372 } 01373 } 01374 01375 return os_snprintf(buf, buflen, 01376 "radiusAuthServerIndex=%d\n" 01377 "radiusAuthServerAddress=%s\n" 01378 "radiusAuthClientServerPortNumber=%d\n" 01379 "radiusAuthClientRoundTripTime=%d\n" 01380 "radiusAuthClientAccessRequests=%u\n" 01381 "radiusAuthClientAccessRetransmissions=%u\n" 01382 "radiusAuthClientAccessAccepts=%u\n" 01383 "radiusAuthClientAccessRejects=%u\n" 01384 "radiusAuthClientAccessChallenges=%u\n" 01385 "radiusAuthClientMalformedAccessResponses=%u\n" 01386 "radiusAuthClientBadAuthenticators=%u\n" 01387 "radiusAuthClientPendingRequests=%u\n" 01388 "radiusAuthClientTimeouts=%u\n" 01389 "radiusAuthClientUnknownTypes=%u\n" 01390 "radiusAuthClientPacketsDropped=%u\n", 01391 serv->index, 01392 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), 01393 serv->port, 01394 serv->round_trip_time, 01395 serv->requests, 01396 serv->retransmissions, 01397 serv->access_accepts, 01398 serv->access_rejects, 01399 serv->access_challenges, 01400 serv->malformed_responses, 01401 serv->bad_authenticators, 01402 pending, 01403 serv->timeouts, 01404 serv->unknown_types, 01405 serv->packets_dropped); 01406 } 01407 01408 01409 static int radius_client_dump_acct_server(char *buf, size_t buflen, 01410 struct hostapd_radius_server *serv, 01411 struct radius_client_data *cli) 01412 { 01413 int pending = 0; 01414 struct radius_msg_list *msg; 01415 char abuf[50]; 01416 01417 if (cli) { 01418 for (msg = cli->msgs; msg; msg = msg->next) { 01419 if (msg->msg_type == RADIUS_ACCT || 01420 msg->msg_type == RADIUS_ACCT_INTERIM) 01421 pending++; 01422 } 01423 } 01424 01425 return os_snprintf(buf, buflen, 01426 "radiusAccServerIndex=%d\n" 01427 "radiusAccServerAddress=%s\n" 01428 "radiusAccClientServerPortNumber=%d\n" 01429 "radiusAccClientRoundTripTime=%d\n" 01430 "radiusAccClientRequests=%u\n" 01431 "radiusAccClientRetransmissions=%u\n" 01432 "radiusAccClientResponses=%u\n" 01433 "radiusAccClientMalformedResponses=%u\n" 01434 "radiusAccClientBadAuthenticators=%u\n" 01435 "radiusAccClientPendingRequests=%u\n" 01436 "radiusAccClientTimeouts=%u\n" 01437 "radiusAccClientUnknownTypes=%u\n" 01438 "radiusAccClientPacketsDropped=%u\n", 01439 serv->index, 01440 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)), 01441 serv->port, 01442 serv->round_trip_time, 01443 serv->requests, 01444 serv->retransmissions, 01445 serv->responses, 01446 serv->malformed_responses, 01447 serv->bad_authenticators, 01448 pending, 01449 serv->timeouts, 01450 serv->unknown_types, 01451 serv->packets_dropped); 01452 } 01453 01454 01462 int radius_client_get_mib(struct radius_client_data *radius, char *buf, 01463 size_t buflen) 01464 { 01465 struct hostapd_radius_servers *conf = radius->conf; 01466 int i; 01467 struct hostapd_radius_server *serv; 01468 int count = 0; 01469 01470 if (conf->auth_servers) { 01471 for (i = 0; i < conf->num_auth_servers; i++) { 01472 serv = &conf->auth_servers[i]; 01473 count += radius_client_dump_auth_server( 01474 buf + count, buflen - count, serv, 01475 serv == conf->auth_server ? 01476 radius : NULL); 01477 } 01478 } 01479 01480 if (conf->acct_servers) { 01481 for (i = 0; i < conf->num_acct_servers; i++) { 01482 serv = &conf->acct_servers[i]; 01483 count += radius_client_dump_acct_server( 01484 buf + count, buflen - count, serv, 01485 serv == conf->acct_server ? 01486 radius : NULL); 01487 } 01488 } 01489 01490 return count; 01491 }