00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
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
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
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
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
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
00528
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
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
00763
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
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
00810 case RADIUS_RX_QUEUED:
00811 radius_client_msg_free(req);
00812 return;
00813 case RADIUS_RX_INVALID_AUTHENTICATOR:
00814 invalid_authenticator++;
00815
00816 case RADIUS_RX_UNKNOWN:
00817
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
00853
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
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
00967
00968
00969
00970
00971
00972
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
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
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
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
01080 }
01081 #endif
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
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
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
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
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
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
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 }