00001
00016 #include "includes.h"
00017
00018 #include "common.h"
00019 #include "radius.h"
00020 #include "radius_client.h"
00021 #include "eloop.h"
00022
00023
00024 #define RADIUS_CLIENT_FIRST_WAIT 3
00025 #define RADIUS_CLIENT_MAX_WAIT 120
00026 #define RADIUS_CLIENT_MAX_RETRIES 10
00027
00028
00029 #define RADIUS_CLIENT_MAX_ENTRIES 30
00030
00031
00032 #define RADIUS_CLIENT_NUM_FAILOVER 4
00033
00034
00035
00036 struct radius_rx_handler {
00037 RadiusRxResult (*handler)(struct radius_msg *msg,
00038 struct radius_msg *req,
00039 const u8 *shared_secret,
00040 size_t shared_secret_len,
00041 void *data);
00042 void *data;
00043 };
00044
00045
00046
00047 struct radius_msg_list {
00048 u8 addr[ETH_ALEN];
00049
00050 struct radius_msg *msg;
00051 RadiusType msg_type;
00052 os_time_t first_try;
00053 os_time_t next_try;
00054 int attempts;
00055 int next_wait;
00056 struct os_time last_attempt;
00057
00058 u8 *shared_secret;
00059 size_t shared_secret_len;
00060
00061
00062
00063 struct radius_msg_list *next;
00064 };
00065
00066
00067 struct radius_client_data {
00068 void *ctx;
00069 struct hostapd_radius_servers *conf;
00070
00071 int auth_serv_sock;
00072 int acct_serv_sock;
00073 int auth_serv_sock6;
00074 int acct_serv_sock6;
00075 int auth_sock;
00076 int acct_sock;
00077
00078 struct radius_rx_handler *auth_handlers;
00079 size_t num_auth_handlers;
00080 struct radius_rx_handler *acct_handlers;
00081 size_t num_acct_handlers;
00082
00083 struct radius_msg_list *msgs;
00084 size_t num_msgs;
00085
00086 u8 next_radius_identifier;
00087 };
00088
00089
00090 static int
00091 radius_change_server(struct radius_client_data *radius,
00092 struct hostapd_radius_server *nserv,
00093 struct hostapd_radius_server *oserv,
00094 int sock, int sock6, int auth);
00095 static int radius_client_init_acct(struct radius_client_data *radius);
00096 static int radius_client_init_auth(struct radius_client_data *radius);
00097
00098
00099 static void radius_client_msg_free(struct radius_msg_list *req)
00100 {
00101 radius_msg_free(req->msg);
00102 os_free(req->msg);
00103 os_free(req);
00104 }
00105
00106
00107 int radius_client_register(struct radius_client_data *radius,
00108 RadiusType msg_type,
00109 RadiusRxResult (*handler)(struct radius_msg *msg,
00110 struct radius_msg *req,
00111 const u8 *shared_secret,
00112 size_t shared_secret_len,
00113 void *data),
00114 void *data)
00115 {
00116 struct radius_rx_handler **handlers, *newh;
00117 size_t *num;
00118
00119 if (msg_type == RADIUS_ACCT) {
00120 handlers = &radius->acct_handlers;
00121 num = &radius->num_acct_handlers;
00122 } else {
00123 handlers = &radius->auth_handlers;
00124 num = &radius->num_auth_handlers;
00125 }
00126
00127 newh = os_realloc(*handlers,
00128 (*num + 1) * sizeof(struct radius_rx_handler));
00129 if (newh == NULL)
00130 return -1;
00131
00132 newh[*num].handler = handler;
00133 newh[*num].data = data;
00134 (*num)++;
00135 *handlers = newh;
00136
00137 return 0;
00138 }
00139
00140
00141 static void radius_client_handle_send_error(struct radius_client_data *radius,
00142 int s, RadiusType msg_type)
00143 {
00144 #ifndef CONFIG_NATIVE_WINDOWS
00145 int _errno = errno;
00146 perror("send[RADIUS]");
00147 if (_errno == ENOTCONN || _errno == EDESTADDRREQ || _errno == EINVAL ||
00148 _errno == EBADF) {
00149 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00150 HOSTAPD_LEVEL_INFO,
00151 "Send failed - maybe interface status changed -"
00152 " try to connect again");
00153 eloop_unregister_read_sock(s);
00154 close(s);
00155 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM)
00156 radius_client_init_acct(radius);
00157 else
00158 radius_client_init_auth(radius);
00159 }
00160 #endif
00161 }
00162
00163
00164 static int radius_client_retransmit(struct radius_client_data *radius,
00165 struct radius_msg_list *entry,
00166 os_time_t now)
00167 {
00168 struct hostapd_radius_servers *conf = radius->conf;
00169 int s;
00170
00171 if (entry->msg_type == RADIUS_ACCT ||
00172 entry->msg_type == RADIUS_ACCT_INTERIM) {
00173 s = radius->acct_sock;
00174 if (entry->attempts == 0)
00175 conf->acct_server->requests++;
00176 else {
00177 conf->acct_server->timeouts++;
00178 conf->acct_server->retransmissions++;
00179 }
00180 } else {
00181 s = radius->auth_sock;
00182 if (entry->attempts == 0)
00183 conf->auth_server->requests++;
00184 else {
00185 conf->auth_server->timeouts++;
00186 conf->auth_server->retransmissions++;
00187 }
00188 }
00189
00190
00191 entry->attempts++;
00192 hostapd_logger(radius->ctx, entry->addr, HOSTAPD_MODULE_RADIUS,
00193 HOSTAPD_LEVEL_DEBUG, "Resending RADIUS message (id=%d)",
00194 entry->msg->hdr->identifier);
00195
00196 os_get_time(&entry->last_attempt);
00197 if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
00198 radius_client_handle_send_error(radius, s, entry->msg_type);
00199
00200 entry->next_try = now + entry->next_wait;
00201 entry->next_wait *= 2;
00202 if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
00203 entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
00204 if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES) {
00205 printf("Removing un-ACKed RADIUS message due to too many "
00206 "failed retransmit attempts\n");
00207 return 1;
00208 }
00209
00210 return 0;
00211 }
00212
00213
00214 static void radius_client_timer(void *eloop_ctx, void *timeout_ctx)
00215 {
00216 struct radius_client_data *radius = eloop_ctx;
00217 struct hostapd_radius_servers *conf = radius->conf;
00218 struct os_time now;
00219 os_time_t first;
00220 struct radius_msg_list *entry, *prev, *tmp;
00221 int auth_failover = 0, acct_failover = 0;
00222 char abuf[50];
00223
00224 entry = radius->msgs;
00225 if (!entry)
00226 return;
00227
00228 os_get_time(&now);
00229 first = 0;
00230
00231 prev = NULL;
00232 while (entry) {
00233 if (now.sec >= entry->next_try &&
00234 radius_client_retransmit(radius, entry, now.sec)) {
00235 if (prev)
00236 prev->next = entry->next;
00237 else
00238 radius->msgs = entry->next;
00239
00240 tmp = entry;
00241 entry = entry->next;
00242 radius_client_msg_free(tmp);
00243 radius->num_msgs--;
00244 continue;
00245 }
00246
00247 if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER) {
00248 if (entry->msg_type == RADIUS_ACCT ||
00249 entry->msg_type == RADIUS_ACCT_INTERIM)
00250 acct_failover++;
00251 else
00252 auth_failover++;
00253 }
00254
00255 if (first == 0 || entry->next_try < first)
00256 first = entry->next_try;
00257
00258 prev = entry;
00259 entry = entry->next;
00260 }
00261
00262 if (radius->msgs) {
00263 if (first < now.sec)
00264 first = now.sec;
00265 eloop_register_timeout(first - now.sec, 0,
00266 radius_client_timer, radius, NULL);
00267 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00268 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client "
00269 "retransmit in %ld seconds",
00270 (long int) (first - now.sec));
00271 }
00272
00273 if (auth_failover && conf->num_auth_servers > 1) {
00274 struct hostapd_radius_server *next, *old;
00275 old = conf->auth_server;
00276 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00277 HOSTAPD_LEVEL_NOTICE,
00278 "No response from Authentication server "
00279 "%s:%d - failover",
00280 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
00281 old->port);
00282
00283 for (entry = radius->msgs; entry; entry = entry->next) {
00284 if (entry->msg_type == RADIUS_AUTH)
00285 old->timeouts++;
00286 }
00287
00288 next = old + 1;
00289 if (next > &(conf->auth_servers[conf->num_auth_servers - 1]))
00290 next = conf->auth_servers;
00291 conf->auth_server = next;
00292 radius_change_server(radius, next, old,
00293 radius->auth_serv_sock,
00294 radius->auth_serv_sock6, 1);
00295 }
00296
00297 if (acct_failover && conf->num_acct_servers > 1) {
00298 struct hostapd_radius_server *next, *old;
00299 old = conf->acct_server;
00300 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00301 HOSTAPD_LEVEL_NOTICE,
00302 "No response from Accounting server "
00303 "%s:%d - failover",
00304 hostapd_ip_txt(&old->addr, abuf, sizeof(abuf)),
00305 old->port);
00306
00307 for (entry = radius->msgs; entry; entry = entry->next) {
00308 if (entry->msg_type == RADIUS_ACCT ||
00309 entry->msg_type == RADIUS_ACCT_INTERIM)
00310 old->timeouts++;
00311 }
00312
00313 next = old + 1;
00314 if (next > &conf->acct_servers[conf->num_acct_servers - 1])
00315 next = conf->acct_servers;
00316 conf->acct_server = next;
00317 radius_change_server(radius, next, old,
00318 radius->acct_serv_sock,
00319 radius->acct_serv_sock6, 0);
00320 }
00321 }
00322
00323
00324 static void radius_client_update_timeout(struct radius_client_data *radius)
00325 {
00326 struct os_time now;
00327 os_time_t first;
00328 struct radius_msg_list *entry;
00329
00330 eloop_cancel_timeout(radius_client_timer, radius, NULL);
00331
00332 if (radius->msgs == NULL) {
00333 return;
00334 }
00335
00336 first = 0;
00337 for (entry = radius->msgs; entry; entry = entry->next) {
00338 if (first == 0 || entry->next_try < first)
00339 first = entry->next_try;
00340 }
00341
00342 os_get_time(&now);
00343 if (first < now.sec)
00344 first = now.sec;
00345 eloop_register_timeout(first - now.sec, 0, radius_client_timer, radius,
00346 NULL);
00347 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00348 HOSTAPD_LEVEL_DEBUG, "Next RADIUS client retransmit in"
00349 " %ld seconds\n", (long int) (first - now.sec));
00350 }
00351
00352
00353 static void radius_client_list_add(struct radius_client_data *radius,
00354 struct radius_msg *msg,
00355 RadiusType msg_type, u8 *shared_secret,
00356 size_t shared_secret_len, const u8 *addr)
00357 {
00358 struct radius_msg_list *entry, *prev;
00359
00360 if (eloop_terminated()) {
00361
00362
00363 radius_msg_free(msg);
00364 os_free(msg);
00365 return;
00366 }
00367
00368 entry = os_zalloc(sizeof(*entry));
00369 if (entry == NULL) {
00370 printf("Failed to add RADIUS packet into retransmit list\n");
00371 radius_msg_free(msg);
00372 os_free(msg);
00373 return;
00374 }
00375
00376 if (addr)
00377 os_memcpy(entry->addr, addr, ETH_ALEN);
00378 entry->msg = msg;
00379 entry->msg_type = msg_type;
00380 entry->shared_secret = shared_secret;
00381 entry->shared_secret_len = shared_secret_len;
00382 os_get_time(&entry->last_attempt);
00383 entry->first_try = entry->last_attempt.sec;
00384 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
00385 entry->attempts = 1;
00386 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
00387 entry->next = radius->msgs;
00388 radius->msgs = entry;
00389 radius_client_update_timeout(radius);
00390
00391 if (radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES) {
00392 printf("Removing the oldest un-ACKed RADIUS packet due to "
00393 "retransmit list limits.\n");
00394 prev = NULL;
00395 while (entry->next) {
00396 prev = entry;
00397 entry = entry->next;
00398 }
00399 if (prev) {
00400 prev->next = NULL;
00401 radius_client_msg_free(entry);
00402 }
00403 } else
00404 radius->num_msgs++;
00405 }
00406
00407
00408 static void radius_client_list_del(struct radius_client_data *radius,
00409 RadiusType msg_type, const u8 *addr)
00410 {
00411 struct radius_msg_list *entry, *prev, *tmp;
00412
00413 if (addr == NULL)
00414 return;
00415
00416 entry = radius->msgs;
00417 prev = NULL;
00418 while (entry) {
00419 if (entry->msg_type == msg_type &&
00420 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
00421 if (prev)
00422 prev->next = entry->next;
00423 else
00424 radius->msgs = entry->next;
00425 tmp = entry;
00426 entry = entry->next;
00427 hostapd_logger(radius->ctx, addr,
00428 HOSTAPD_MODULE_RADIUS,
00429 HOSTAPD_LEVEL_DEBUG,
00430 "Removing matching RADIUS message");
00431 radius_client_msg_free(tmp);
00432 radius->num_msgs--;
00433 continue;
00434 }
00435 prev = entry;
00436 entry = entry->next;
00437 }
00438 }
00439
00440
00441 int radius_client_send(struct radius_client_data *radius,
00442 struct radius_msg *msg, RadiusType msg_type,
00443 const u8 *addr)
00444 {
00445 struct hostapd_radius_servers *conf = radius->conf;
00446 u8 *shared_secret;
00447 size_t shared_secret_len;
00448 char *name;
00449 int s, res;
00450
00451 if (msg_type == RADIUS_ACCT_INTERIM) {
00452
00453 radius_client_list_del(radius, msg_type, addr);
00454 }
00455
00456 if (msg_type == RADIUS_ACCT || msg_type == RADIUS_ACCT_INTERIM) {
00457 if (conf->acct_server == NULL) {
00458 hostapd_logger(radius->ctx, NULL,
00459 HOSTAPD_MODULE_RADIUS,
00460 HOSTAPD_LEVEL_INFO,
00461 "No accounting server configured");
00462 return -1;
00463 }
00464 shared_secret = conf->acct_server->shared_secret;
00465 shared_secret_len = conf->acct_server->shared_secret_len;
00466 radius_msg_finish_acct(msg, shared_secret, shared_secret_len);
00467 name = "accounting";
00468 s = radius->acct_sock;
00469 conf->acct_server->requests++;
00470 } else {
00471 if (conf->auth_server == NULL) {
00472 hostapd_logger(radius->ctx, NULL,
00473 HOSTAPD_MODULE_RADIUS,
00474 HOSTAPD_LEVEL_INFO,
00475 "No authentication server configured");
00476 return -1;
00477 }
00478 shared_secret = conf->auth_server->shared_secret;
00479 shared_secret_len = conf->auth_server->shared_secret_len;
00480 radius_msg_finish(msg, shared_secret, shared_secret_len);
00481 name = "authentication";
00482 s = radius->auth_sock;
00483 conf->auth_server->requests++;
00484 }
00485
00486 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00487 HOSTAPD_LEVEL_DEBUG, "Sending RADIUS message to %s "
00488 "server", name);
00489 if (conf->msg_dumps)
00490 radius_msg_dump(msg);
00491
00492 res = send(s, msg->buf, msg->buf_used, 0);
00493 if (res < 0)
00494 radius_client_handle_send_error(radius, s, msg_type);
00495
00496 radius_client_list_add(radius, msg, msg_type, shared_secret,
00497 shared_secret_len, addr);
00498
00499 return res;
00500 }
00501
00502
00503 static void radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
00504 {
00505 struct radius_client_data *radius = eloop_ctx;
00506 struct hostapd_radius_servers *conf = radius->conf;
00507 RadiusType msg_type = (RadiusType) sock_ctx;
00508 int len, roundtrip;
00509 unsigned char buf[3000];
00510 struct radius_msg *msg;
00511 struct radius_rx_handler *handlers;
00512 size_t num_handlers, i;
00513 struct radius_msg_list *req, *prev_req;
00514 struct os_time now;
00515 struct hostapd_radius_server *rconf;
00516 int invalid_authenticator = 0;
00517
00518 if (msg_type == RADIUS_ACCT) {
00519 handlers = radius->acct_handlers;
00520 num_handlers = radius->num_acct_handlers;
00521 rconf = conf->acct_server;
00522 } else {
00523 handlers = radius->auth_handlers;
00524 num_handlers = radius->num_auth_handlers;
00525 rconf = conf->auth_server;
00526 }
00527
00528 len = recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
00529 if (len < 0) {
00530 perror("recv[RADIUS]");
00531 return;
00532 }
00533 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00534 HOSTAPD_LEVEL_DEBUG, "Received %d bytes from RADIUS "
00535 "server", len);
00536 if (len == sizeof(buf)) {
00537 printf("Possibly too long UDP frame for our buffer - "
00538 "dropping it\n");
00539 return;
00540 }
00541
00542 msg = radius_msg_parse(buf, len);
00543 if (msg == NULL) {
00544 printf("Parsing incoming RADIUS frame failed\n");
00545 rconf->malformed_responses++;
00546 return;
00547 }
00548
00549 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00550 HOSTAPD_LEVEL_DEBUG, "Received RADIUS message");
00551 if (conf->msg_dumps)
00552 radius_msg_dump(msg);
00553
00554 switch (msg->hdr->code) {
00555 case RADIUS_CODE_ACCESS_ACCEPT:
00556 rconf->access_accepts++;
00557 break;
00558 case RADIUS_CODE_ACCESS_REJECT:
00559 rconf->access_rejects++;
00560 break;
00561 case RADIUS_CODE_ACCESS_CHALLENGE:
00562 rconf->access_challenges++;
00563 break;
00564 case RADIUS_CODE_ACCOUNTING_RESPONSE:
00565 rconf->responses++;
00566 break;
00567 }
00568
00569 prev_req = NULL;
00570 req = radius->msgs;
00571 while (req) {
00572
00573
00574 if ((req->msg_type == msg_type ||
00575 (req->msg_type == RADIUS_ACCT_INTERIM &&
00576 msg_type == RADIUS_ACCT)) &&
00577 req->msg->hdr->identifier == msg->hdr->identifier)
00578 break;
00579
00580 prev_req = req;
00581 req = req->next;
00582 }
00583
00584 if (req == NULL) {
00585 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00586 HOSTAPD_LEVEL_DEBUG,
00587 "No matching RADIUS request found (type=%d "
00588 "id=%d) - dropping packet",
00589 msg_type, msg->hdr->identifier);
00590 goto fail;
00591 }
00592
00593 os_get_time(&now);
00594 roundtrip = (now.sec - req->last_attempt.sec) * 100 +
00595 (now.usec - req->last_attempt.usec) / 10000;
00596 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
00597 HOSTAPD_LEVEL_DEBUG,
00598 "Received RADIUS packet matched with a pending "
00599 "request, round trip time %d.%02d sec",
00600 roundtrip / 100, roundtrip % 100);
00601 rconf->round_trip_time = roundtrip;
00602
00603
00604 if (prev_req)
00605 prev_req->next = req->next;
00606 else
00607 radius->msgs = req->next;
00608 radius->num_msgs--;
00609
00610 for (i = 0; i < num_handlers; i++) {
00611 RadiusRxResult res;
00612 res = handlers[i].handler(msg, req->msg, req->shared_secret,
00613 req->shared_secret_len,
00614 handlers[i].data);
00615 switch (res) {
00616 case RADIUS_RX_PROCESSED:
00617 radius_msg_free(msg);
00618 os_free(msg);
00619
00620 case RADIUS_RX_QUEUED:
00621 radius_client_msg_free(req);
00622 return;
00623 case RADIUS_RX_INVALID_AUTHENTICATOR:
00624 invalid_authenticator++;
00625
00626 case RADIUS_RX_UNKNOWN:
00627
00628 break;
00629 }
00630 }
00631
00632 if (invalid_authenticator)
00633 rconf->bad_authenticators++;
00634 else
00635 rconf->unknown_types++;
00636 hostapd_logger(radius->ctx, req->addr, HOSTAPD_MODULE_RADIUS,
00637 HOSTAPD_LEVEL_DEBUG, "No RADIUS RX handler found "
00638 "(type=%d code=%d id=%d)%s - dropping packet",
00639 msg_type, msg->hdr->code, msg->hdr->identifier,
00640 invalid_authenticator ? " [INVALID AUTHENTICATOR]" :
00641 "");
00642 radius_client_msg_free(req);
00643
00644 fail:
00645 radius_msg_free(msg);
00646 os_free(msg);
00647 }
00648
00649
00650 u8 radius_client_get_id(struct radius_client_data *radius)
00651 {
00652 struct radius_msg_list *entry, *prev, *_remove;
00653 u8 id = radius->next_radius_identifier++;
00654
00655
00656
00657 entry = radius->msgs;
00658 prev = NULL;
00659 while (entry) {
00660 if (entry->msg->hdr->identifier == id) {
00661 hostapd_logger(radius->ctx, entry->addr,
00662 HOSTAPD_MODULE_RADIUS,
00663 HOSTAPD_LEVEL_DEBUG,
00664 "Removing pending RADIUS message, "
00665 "since its id (%d) is reused", id);
00666 if (prev)
00667 prev->next = entry->next;
00668 else
00669 radius->msgs = entry->next;
00670 _remove = entry;
00671 } else {
00672 _remove = NULL;
00673 prev = entry;
00674 }
00675 entry = entry->next;
00676
00677 if (_remove)
00678 radius_client_msg_free(_remove);
00679 }
00680
00681 return id;
00682 }
00683
00684
00685 void radius_client_flush(struct radius_client_data *radius, int only_auth)
00686 {
00687 struct radius_msg_list *entry, *prev, *tmp;
00688
00689 if (!radius)
00690 return;
00691
00692 prev = NULL;
00693 entry = radius->msgs;
00694
00695 while (entry) {
00696 if (!only_auth || entry->msg_type == RADIUS_AUTH) {
00697 if (prev)
00698 prev->next = entry->next;
00699 else
00700 radius->msgs = entry->next;
00701
00702 tmp = entry;
00703 entry = entry->next;
00704 radius_client_msg_free(tmp);
00705 radius->num_msgs--;
00706 } else {
00707 prev = entry;
00708 entry = entry->next;
00709 }
00710 }
00711
00712 if (radius->msgs == NULL)
00713 eloop_cancel_timeout(radius_client_timer, radius, NULL);
00714 }
00715
00716
00717 static void radius_client_update_acct_msgs(struct radius_client_data *radius,
00718 u8 *shared_secret,
00719 size_t shared_secret_len)
00720 {
00721 struct radius_msg_list *entry;
00722
00723 if (!radius)
00724 return;
00725
00726 for (entry = radius->msgs; entry; entry = entry->next) {
00727 if (entry->msg_type == RADIUS_ACCT) {
00728 entry->shared_secret = shared_secret;
00729 entry->shared_secret_len = shared_secret_len;
00730 radius_msg_finish_acct(entry->msg, shared_secret,
00731 shared_secret_len);
00732 }
00733 }
00734 }
00735
00736
00737 static int
00738 radius_change_server(struct radius_client_data *radius,
00739 struct hostapd_radius_server *nserv,
00740 struct hostapd_radius_server *oserv,
00741 int sock, int sock6, int auth)
00742 {
00743 struct sockaddr_in serv, claddr;
00744 #ifdef CONFIG_IPV6
00745 struct sockaddr_in6 serv6, claddr6;
00746 #endif
00747 struct sockaddr *addr, *cl_addr;
00748 socklen_t addrlen, claddrlen;
00749 char abuf[50];
00750 int sel_sock;
00751 struct radius_msg_list *entry;
00752 struct hostapd_radius_servers *conf = radius->conf;
00753
00754 hostapd_logger(radius->ctx, NULL, HOSTAPD_MODULE_RADIUS,
00755 HOSTAPD_LEVEL_INFO,
00756 "%s server %s:%d",
00757 auth ? "Authentication" : "Accounting",
00758 hostapd_ip_txt(&nserv->addr, abuf, sizeof(abuf)),
00759 nserv->port);
00760
00761 if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
00762 os_memcmp(nserv->shared_secret, oserv->shared_secret,
00763 nserv->shared_secret_len) != 0) {
00764
00765
00766
00767
00768
00769
00770
00771 if (auth)
00772 radius_client_flush(radius, 1);
00773 else {
00774 radius_client_update_acct_msgs(
00775 radius, nserv->shared_secret,
00776 nserv->shared_secret_len);
00777 }
00778 }
00779
00780
00781 for (entry = radius->msgs; entry; entry = entry->next) {
00782 if ((auth && entry->msg_type != RADIUS_AUTH) ||
00783 (!auth && entry->msg_type != RADIUS_ACCT))
00784 continue;
00785 entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
00786 entry->attempts = 0;
00787 entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
00788 }
00789
00790 if (radius->msgs) {
00791 eloop_cancel_timeout(radius_client_timer, radius, NULL);
00792 eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0,
00793 radius_client_timer, radius, NULL);
00794 }
00795
00796 switch (nserv->addr.af) {
00797 case AF_INET:
00798 os_memset(&serv, 0, sizeof(serv));
00799 serv.sin_family = AF_INET;
00800 serv.sin_addr.s_addr = nserv->addr.u.v4.s_addr;
00801 serv.sin_port = htons(nserv->port);
00802 addr = (struct sockaddr *) &serv;
00803 addrlen = sizeof(serv);
00804 sel_sock = sock;
00805 break;
00806 #ifdef CONFIG_IPV6
00807 case AF_INET6:
00808 os_memset(&serv6, 0, sizeof(serv6));
00809 serv6.sin6_family = AF_INET6;
00810 os_memcpy(&serv6.sin6_addr, &nserv->addr.u.v6,
00811 sizeof(struct in6_addr));
00812 serv6.sin6_port = htons(nserv->port);
00813 addr = (struct sockaddr *) &serv6;
00814 addrlen = sizeof(serv6);
00815 sel_sock = sock6;
00816 break;
00817 #endif
00818 default:
00819 return -1;
00820 }
00821
00822 if (conf->force_client_addr) {
00823 switch (conf->client_addr.af) {
00824 case AF_INET:
00825 os_memset(&claddr, 0, sizeof(claddr));
00826 claddr.sin_family = AF_INET;
00827 claddr.sin_addr.s_addr = conf->client_addr.u.v4.s_addr;
00828 claddr.sin_port = htons(0);
00829 cl_addr = (struct sockaddr *) &claddr;
00830 claddrlen = sizeof(claddr);
00831 break;
00832 #ifdef CONFIG_IPV6
00833 case AF_INET6:
00834 os_memset(&claddr6, 0, sizeof(claddr6));
00835 claddr6.sin6_family = AF_INET6;
00836 os_memcpy(&claddr6.sin6_addr, &conf->client_addr.u.v6,
00837 sizeof(struct in6_addr));
00838 claddr6.sin6_port = htons(0);
00839 cl_addr = (struct sockaddr *) &claddr6;
00840 claddrlen = sizeof(claddr6);
00841 break;
00842 #endif
00843 default:
00844 return -1;
00845 }
00846
00847 if (bind(sel_sock, cl_addr, claddrlen) < 0) {
00848 perror("bind[radius]");
00849 return -1;
00850 }
00851 }
00852
00853 if (connect(sel_sock, addr, addrlen) < 0) {
00854 perror("connect[radius]");
00855 return -1;
00856 }
00857
00858 #ifndef CONFIG_NATIVE_WINDOWS
00859 switch (nserv->addr.af) {
00860 case AF_INET:
00861 claddrlen = sizeof(claddr);
00862 getsockname(sel_sock, (struct sockaddr *) &claddr, &claddrlen);
00863 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
00864 inet_ntoa(claddr.sin_addr), ntohs(claddr.sin_port));
00865 break;
00866 #ifdef CONFIG_IPV6
00867 case AF_INET6: {
00868 claddrlen = sizeof(claddr6);
00869 getsockname(sel_sock, (struct sockaddr *) &claddr6,
00870 &claddrlen);
00871 wpa_printf(MSG_DEBUG, "RADIUS local address: %s:%u",
00872 inet_ntop(AF_INET6, &claddr6.sin6_addr,
00873 abuf, sizeof(abuf)),
00874 ntohs(claddr6.sin6_port));
00875 break;
00876 }
00877 #endif
00878 }
00879 #endif
00880
00881 if (auth)
00882 radius->auth_sock = sel_sock;
00883 else
00884 radius->acct_sock = sel_sock;
00885
00886 return 0;
00887 }
00888
00889
00890 static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
00891 {
00892 struct radius_client_data *radius = eloop_ctx;
00893 struct hostapd_radius_servers *conf = radius->conf;
00894 struct hostapd_radius_server *oserv;
00895
00896 if (radius->auth_sock >= 0 && conf->auth_servers &&
00897 conf->auth_server != conf->auth_servers) {
00898 oserv = conf->auth_server;
00899 conf->auth_server = conf->auth_servers;
00900 radius_change_server(radius, conf->auth_server, oserv,
00901 radius->auth_serv_sock,
00902 radius->auth_serv_sock6, 1);
00903 }
00904
00905 if (radius->acct_sock >= 0 && conf->acct_servers &&
00906 conf->acct_server != conf->acct_servers) {
00907 oserv = conf->acct_server;
00908 conf->acct_server = conf->acct_servers;
00909 radius_change_server(radius, conf->acct_server, oserv,
00910 radius->acct_serv_sock,
00911 radius->acct_serv_sock6, 0);
00912 }
00913
00914 if (conf->retry_primary_interval)
00915 eloop_register_timeout(conf->retry_primary_interval, 0,
00916 radius_retry_primary_timer, radius,
00917 NULL);
00918 }
00919
00920
00921 static int radius_client_disable_pmtu_discovery(int s)
00922 {
00923 int r = -1;
00924 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
00925
00926 int action = IP_PMTUDISC_DONT;
00927 r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
00928 sizeof(action));
00929 if (r == -1)
00930 wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
00931 "%s", strerror(errno));
00932 #endif
00933 return r;
00934 }
00935
00936
00937 static int radius_client_init_auth(struct radius_client_data *radius)
00938 {
00939 struct hostapd_radius_servers *conf = radius->conf;
00940 int ok = 0;
00941
00942 radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
00943 if (radius->auth_serv_sock < 0)
00944 perror("socket[PF_INET,SOCK_DGRAM]");
00945 else {
00946 radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
00947 ok++;
00948 }
00949
00950 #ifdef CONFIG_IPV6
00951 radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
00952 if (radius->auth_serv_sock6 < 0)
00953 perror("socket[PF_INET6,SOCK_DGRAM]");
00954 else
00955 ok++;
00956 #endif
00957
00958 if (ok == 0)
00959 return -1;
00960
00961 radius_change_server(radius, conf->auth_server, NULL,
00962 radius->auth_serv_sock, radius->auth_serv_sock6,
00963 1);
00964
00965 if (radius->auth_serv_sock >= 0 &&
00966 eloop_register_read_sock(radius->auth_serv_sock,
00967 radius_client_receive, radius,
00968 (void *) RADIUS_AUTH)) {
00969 printf("Could not register read socket for authentication "
00970 "server\n");
00971 return -1;
00972 }
00973
00974 #ifdef CONFIG_IPV6
00975 if (radius->auth_serv_sock6 >= 0 &&
00976 eloop_register_read_sock(radius->auth_serv_sock6,
00977 radius_client_receive, radius,
00978 (void *) RADIUS_AUTH)) {
00979 printf("Could not register read socket for authentication "
00980 "server\n");
00981 return -1;
00982 }
00983 #endif
00984
00985 return 0;
00986 }
00987
00988
00989 static int radius_client_init_acct(struct radius_client_data *radius)
00990 {
00991 struct hostapd_radius_servers *conf = radius->conf;
00992 int ok = 0;
00993
00994 radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
00995 if (radius->acct_serv_sock < 0)
00996 perror("socket[PF_INET,SOCK_DGRAM]");
00997 else {
00998 radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
00999 ok++;
01000 }
01001
01002 #ifdef CONFIG_IPV6
01003 radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
01004 if (radius->acct_serv_sock6 < 0)
01005 perror("socket[PF_INET6,SOCK_DGRAM]");
01006 else
01007 ok++;
01008 #endif
01009
01010 if (ok == 0)
01011 return -1;
01012
01013 radius_change_server(radius, conf->acct_server, NULL,
01014 radius->acct_serv_sock, radius->acct_serv_sock6,
01015 0);
01016
01017 if (radius->acct_serv_sock >= 0 &&
01018 eloop_register_read_sock(radius->acct_serv_sock,
01019 radius_client_receive, radius,
01020 (void *) RADIUS_ACCT)) {
01021 printf("Could not register read socket for accounting "
01022 "server\n");
01023 return -1;
01024 }
01025
01026 #ifdef CONFIG_IPV6
01027 if (radius->acct_serv_sock6 >= 0 &&
01028 eloop_register_read_sock(radius->acct_serv_sock6,
01029 radius_client_receive, radius,
01030 (void *) RADIUS_ACCT)) {
01031 printf("Could not register read socket for accounting "
01032 "server\n");
01033 return -1;
01034 }
01035 #endif
01036
01037 return 0;
01038 }
01039
01040
01041 struct radius_client_data *
01042 radius_client_init(void *ctx, struct hostapd_radius_servers *conf)
01043 {
01044 struct radius_client_data *radius;
01045
01046 radius = os_zalloc(sizeof(struct radius_client_data));
01047 if (radius == NULL)
01048 return NULL;
01049
01050 radius->ctx = ctx;
01051 radius->conf = conf;
01052 radius->auth_serv_sock = radius->acct_serv_sock =
01053 radius->auth_serv_sock6 = radius->acct_serv_sock6 =
01054 radius->auth_sock = radius->acct_sock = -1;
01055
01056 if (conf->auth_server && radius_client_init_auth(radius)) {
01057 radius_client_deinit(radius);
01058 return NULL;
01059 }
01060
01061 if (conf->acct_server && radius_client_init_acct(radius)) {
01062 radius_client_deinit(radius);
01063 return NULL;
01064 }
01065
01066 if (conf->retry_primary_interval)
01067 eloop_register_timeout(conf->retry_primary_interval, 0,
01068 radius_retry_primary_timer, radius,
01069 NULL);
01070
01071 return radius;
01072 }
01073
01074
01075 void radius_client_deinit(struct radius_client_data *radius)
01076 {
01077 if (!radius)
01078 return;
01079
01080 if (radius->auth_serv_sock >= 0)
01081 eloop_unregister_read_sock(radius->auth_serv_sock);
01082 if (radius->acct_serv_sock >= 0)
01083 eloop_unregister_read_sock(radius->acct_serv_sock);
01084
01085 eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
01086
01087 radius_client_flush(radius, 0);
01088 os_free(radius->auth_handlers);
01089 os_free(radius->acct_handlers);
01090 os_free(radius);
01091 }
01092
01093
01094 void radius_client_flush_auth(struct radius_client_data *radius, u8 *addr)
01095 {
01096 struct radius_msg_list *entry, *prev, *tmp;
01097
01098 prev = NULL;
01099 entry = radius->msgs;
01100 while (entry) {
01101 if (entry->msg_type == RADIUS_AUTH &&
01102 os_memcmp(entry->addr, addr, ETH_ALEN) == 0) {
01103 hostapd_logger(radius->ctx, addr,
01104 HOSTAPD_MODULE_RADIUS,
01105 HOSTAPD_LEVEL_DEBUG,
01106 "Removing pending RADIUS authentication"
01107 " message for removed client");
01108
01109 if (prev)
01110 prev->next = entry->next;
01111 else
01112 radius->msgs = entry->next;
01113
01114 tmp = entry;
01115 entry = entry->next;
01116 radius_client_msg_free(tmp);
01117 radius->num_msgs--;
01118 continue;
01119 }
01120
01121 prev = entry;
01122 entry = entry->next;
01123 }
01124 }
01125
01126
01127 static int radius_client_dump_auth_server(char *buf, size_t buflen,
01128 struct hostapd_radius_server *serv,
01129 struct radius_client_data *cli)
01130 {
01131 int pending = 0;
01132 struct radius_msg_list *msg;
01133 char abuf[50];
01134
01135 if (cli) {
01136 for (msg = cli->msgs; msg; msg = msg->next) {
01137 if (msg->msg_type == RADIUS_AUTH)
01138 pending++;
01139 }
01140 }
01141
01142 return os_snprintf(buf, buflen,
01143 "radiusAuthServerIndex=%d\n"
01144 "radiusAuthServerAddress=%s\n"
01145 "radiusAuthClientServerPortNumber=%d\n"
01146 "radiusAuthClientRoundTripTime=%d\n"
01147 "radiusAuthClientAccessRequests=%u\n"
01148 "radiusAuthClientAccessRetransmissions=%u\n"
01149 "radiusAuthClientAccessAccepts=%u\n"
01150 "radiusAuthClientAccessRejects=%u\n"
01151 "radiusAuthClientAccessChallenges=%u\n"
01152 "radiusAuthClientMalformedAccessResponses=%u\n"
01153 "radiusAuthClientBadAuthenticators=%u\n"
01154 "radiusAuthClientPendingRequests=%u\n"
01155 "radiusAuthClientTimeouts=%u\n"
01156 "radiusAuthClientUnknownTypes=%u\n"
01157 "radiusAuthClientPacketsDropped=%u\n",
01158 serv->index,
01159 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
01160 serv->port,
01161 serv->round_trip_time,
01162 serv->requests,
01163 serv->retransmissions,
01164 serv->access_accepts,
01165 serv->access_rejects,
01166 serv->access_challenges,
01167 serv->malformed_responses,
01168 serv->bad_authenticators,
01169 pending,
01170 serv->timeouts,
01171 serv->unknown_types,
01172 serv->packets_dropped);
01173 }
01174
01175
01176 static int radius_client_dump_acct_server(char *buf, size_t buflen,
01177 struct hostapd_radius_server *serv,
01178 struct radius_client_data *cli)
01179 {
01180 int pending = 0;
01181 struct radius_msg_list *msg;
01182 char abuf[50];
01183
01184 if (cli) {
01185 for (msg = cli->msgs; msg; msg = msg->next) {
01186 if (msg->msg_type == RADIUS_ACCT ||
01187 msg->msg_type == RADIUS_ACCT_INTERIM)
01188 pending++;
01189 }
01190 }
01191
01192 return os_snprintf(buf, buflen,
01193 "radiusAccServerIndex=%d\n"
01194 "radiusAccServerAddress=%s\n"
01195 "radiusAccClientServerPortNumber=%d\n"
01196 "radiusAccClientRoundTripTime=%d\n"
01197 "radiusAccClientRequests=%u\n"
01198 "radiusAccClientRetransmissions=%u\n"
01199 "radiusAccClientResponses=%u\n"
01200 "radiusAccClientMalformedResponses=%u\n"
01201 "radiusAccClientBadAuthenticators=%u\n"
01202 "radiusAccClientPendingRequests=%u\n"
01203 "radiusAccClientTimeouts=%u\n"
01204 "radiusAccClientUnknownTypes=%u\n"
01205 "radiusAccClientPacketsDropped=%u\n",
01206 serv->index,
01207 hostapd_ip_txt(&serv->addr, abuf, sizeof(abuf)),
01208 serv->port,
01209 serv->round_trip_time,
01210 serv->requests,
01211 serv->retransmissions,
01212 serv->responses,
01213 serv->malformed_responses,
01214 serv->bad_authenticators,
01215 pending,
01216 serv->timeouts,
01217 serv->unknown_types,
01218 serv->packets_dropped);
01219 }
01220
01221
01222 int radius_client_get_mib(struct radius_client_data *radius, char *buf,
01223 size_t buflen)
01224 {
01225 struct hostapd_radius_servers *conf = radius->conf;
01226 int i;
01227 struct hostapd_radius_server *serv;
01228 int count = 0;
01229
01230 if (conf->auth_servers) {
01231 for (i = 0; i < conf->num_auth_servers; i++) {
01232 serv = &conf->auth_servers[i];
01233 count += radius_client_dump_auth_server(
01234 buf + count, buflen - count, serv,
01235 serv == conf->auth_server ?
01236 radius : NULL);
01237 }
01238 }
01239
01240 if (conf->acct_servers) {
01241 for (i = 0; i < conf->num_acct_servers; i++) {
01242 serv = &conf->acct_servers[i];
01243 count += radius_client_dump_acct_server(
01244 buf + count, buflen - count, serv,
01245 serv == conf->acct_server ?
01246 radius : NULL);
01247 }
01248 }
01249
01250 return count;
01251 }
01252
01253
01254 static int radius_servers_diff(struct hostapd_radius_server *nserv,
01255 struct hostapd_radius_server *oserv,
01256 int num)
01257 {
01258 int i;
01259
01260 for (i = 0; i < num; i++) {
01261 if (hostapd_ip_diff(&nserv[i].addr, &oserv[i].addr) ||
01262 nserv[i].port != oserv[i].port ||
01263 nserv[i].shared_secret_len != oserv[i].shared_secret_len ||
01264 os_memcmp(nserv[i].shared_secret, oserv[i].shared_secret,
01265 nserv[i].shared_secret_len) != 0)
01266 return 1;
01267 }
01268
01269 return 0;
01270 }
01271
01272
01273 struct radius_client_data *
01274 radius_client_reconfig(struct radius_client_data *old, void *ctx,
01275 struct hostapd_radius_servers *oldconf,
01276 struct hostapd_radius_servers *newconf)
01277 {
01278 radius_client_flush(old, 0);
01279
01280 if (newconf->retry_primary_interval !=
01281 oldconf->retry_primary_interval ||
01282 newconf->num_auth_servers != oldconf->num_auth_servers ||
01283 newconf->num_acct_servers != oldconf->num_acct_servers ||
01284 radius_servers_diff(newconf->auth_servers, oldconf->auth_servers,
01285 newconf->num_auth_servers) ||
01286 radius_servers_diff(newconf->acct_servers, oldconf->acct_servers,
01287 newconf->num_acct_servers)) {
01288 hostapd_logger(ctx, NULL, HOSTAPD_MODULE_RADIUS,
01289 HOSTAPD_LEVEL_DEBUG,
01290 "Reconfiguring RADIUS client");
01291 radius_client_deinit(old);
01292 return radius_client_init(ctx, newconf);
01293 }
01294
01295 return old;
01296 }
01297