radius_client.c
Go to the documentation of this file.
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 }


wpa_supplicant
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:34:35