radius_server.c

Go to the documentation of this file.
00001 
00016 #include "includes.h"
00017 #include <net/if.h>
00018 
00019 #include "common.h"
00020 #include "radius.h"
00021 #include "eloop.h"
00022 #include "defs.h"
00023 #include "eap_server/eap.h"
00024 #include "radius_server.h"
00025 
00026 #define RADIUS_SESSION_TIMEOUT 60
00027 #define RADIUS_MAX_SESSION 100
00028 #define RADIUS_MAX_MSG_LEN 3000
00029 
00030 static struct eapol_callbacks radius_server_eapol_cb;
00031 
00032 struct radius_client;
00033 struct radius_server_data;
00034 
00035 struct radius_server_counters {
00036         u32 access_requests;
00037         u32 invalid_requests;
00038         u32 dup_access_requests;
00039         u32 access_accepts;
00040         u32 access_rejects;
00041         u32 access_challenges;
00042         u32 malformed_access_requests;
00043         u32 bad_authenticators;
00044         u32 packets_dropped;
00045         u32 unknown_types;
00046 };
00047 
00048 struct radius_session {
00049         struct radius_session *next;
00050         struct radius_client *client;
00051         struct radius_server_data *server;
00052         unsigned int sess_id;
00053         struct eap_sm *eap;
00054         struct eap_eapol_interface *eap_if;
00055 
00056         struct radius_msg *last_msg;
00057         char *last_from_addr;
00058         int last_from_port;
00059         struct sockaddr_storage last_from;
00060         socklen_t last_fromlen;
00061         u8 last_identifier;
00062         struct radius_msg *last_reply;
00063         u8 last_authenticator[16];
00064 };
00065 
00066 struct radius_client {
00067         struct radius_client *next;
00068         struct in_addr addr;
00069         struct in_addr mask;
00070 #ifdef CONFIG_IPV6
00071         struct in6_addr addr6;
00072         struct in6_addr mask6;
00073 #endif /* CONFIG_IPV6 */
00074         char *shared_secret;
00075         int shared_secret_len;
00076         struct radius_session *sessions;
00077         struct radius_server_counters counters;
00078 };
00079 
00080 struct radius_server_data {
00081         int auth_sock;
00082         struct radius_client *clients;
00083         unsigned int next_sess_id;
00084         void *conf_ctx;
00085         int num_sess;
00086         void *eap_sim_db_priv;
00087         void *ssl_ctx;
00088         u8 *pac_opaque_encr_key;
00089         u8 *eap_fast_a_id;
00090         size_t eap_fast_a_id_len;
00091         char *eap_fast_a_id_info;
00092         int eap_fast_prov;
00093         int pac_key_lifetime;
00094         int pac_key_refresh_time;
00095         int eap_sim_aka_result_ind;
00096         int tnc;
00097         struct wps_context *wps;
00098         int ipv6;
00099         struct os_time start_time;
00100         struct radius_server_counters counters;
00101         int (*get_eap_user)(void *ctx, const u8 *identity, size_t identity_len,
00102                             int phase2, struct eap_user *user);
00103         char *eap_req_id_text;
00104         size_t eap_req_id_text_len;
00105 };
00106 
00107 
00108 extern int wpa_debug_level;
00109 
00110 #define RADIUS_DEBUG(args...) \
00111 wpa_printf(MSG_DEBUG, "RADIUS SRV: " args)
00112 #define RADIUS_ERROR(args...) \
00113 wpa_printf(MSG_ERROR, "RADIUS SRV: " args)
00114 #define RADIUS_DUMP(args...) \
00115 wpa_hexdump(MSG_MSGDUMP, "RADIUS SRV: " args)
00116 #define RADIUS_DUMP_ASCII(args...) \
00117 wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
00118 
00119 
00120 static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
00121 
00122 
00123 
00124 static struct radius_client *
00125 radius_server_get_client(struct radius_server_data *data, struct in_addr *addr,
00126                          int ipv6)
00127 {
00128         struct radius_client *client = data->clients;
00129 
00130         while (client) {
00131 #ifdef CONFIG_IPV6
00132                 if (ipv6) {
00133                         struct in6_addr *addr6;
00134                         int i;
00135 
00136                         addr6 = (struct in6_addr *) addr;
00137                         for (i = 0; i < 16; i++) {
00138                                 if ((addr6->s6_addr[i] &
00139                                      client->mask6.s6_addr[i]) !=
00140                                     (client->addr6.s6_addr[i] &
00141                                      client->mask6.s6_addr[i])) {
00142                                         i = 17;
00143                                         break;
00144                                 }
00145                         }
00146                         if (i == 16) {
00147                                 break;
00148                         }
00149                 }
00150 #endif /* CONFIG_IPV6 */
00151                 if (!ipv6 && (client->addr.s_addr & client->mask.s_addr) ==
00152                     (addr->s_addr & client->mask.s_addr)) {
00153                         break;
00154                 }
00155 
00156                 client = client->next;
00157         }
00158 
00159         return client;
00160 }
00161 
00162 
00163 static struct radius_session *
00164 radius_server_get_session(struct radius_client *client, unsigned int sess_id)
00165 {
00166         struct radius_session *sess = client->sessions;
00167 
00168         while (sess) {
00169                 if (sess->sess_id == sess_id) {
00170                         break;
00171                 }
00172                 sess = sess->next;
00173         }
00174 
00175         return sess;
00176 }
00177 
00178 
00179 static void radius_server_session_free(struct radius_server_data *data,
00180                                        struct radius_session *sess)
00181 {
00182         eloop_cancel_timeout(radius_server_session_timeout, data, sess);
00183         eap_server_sm_deinit(sess->eap);
00184         if (sess->last_msg) {
00185                 radius_msg_free(sess->last_msg);
00186                 os_free(sess->last_msg);
00187         }
00188         os_free(sess->last_from_addr);
00189         if (sess->last_reply) {
00190                 radius_msg_free(sess->last_reply);
00191                 os_free(sess->last_reply);
00192         }
00193         os_free(sess);
00194         data->num_sess--;
00195 }
00196 
00197 
00198 static void radius_server_session_remove_timeout(void *eloop_ctx,
00199                                                  void *timeout_ctx);
00200 
00201 static void radius_server_session_remove(struct radius_server_data *data,
00202                                          struct radius_session *sess)
00203 {
00204         struct radius_client *client = sess->client;
00205         struct radius_session *session, *prev;
00206 
00207         eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
00208 
00209         prev = NULL;
00210         session = client->sessions;
00211         while (session) {
00212                 if (session == sess) {
00213                         if (prev == NULL) {
00214                                 client->sessions = sess->next;
00215                         } else {
00216                                 prev->next = sess->next;
00217                         }
00218                         radius_server_session_free(data, sess);
00219                         break;
00220                 }
00221                 prev = session;
00222                 session = session->next;
00223         }
00224 }
00225 
00226 
00227 static void radius_server_session_remove_timeout(void *eloop_ctx,
00228                                                  void *timeout_ctx)
00229 {
00230         struct radius_server_data *data = eloop_ctx;
00231         struct radius_session *sess = timeout_ctx;
00232         RADIUS_DEBUG("Removing completed session 0x%x", sess->sess_id);
00233         radius_server_session_remove(data, sess);
00234 }
00235 
00236 
00237 static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx)
00238 {
00239         struct radius_server_data *data = eloop_ctx;
00240         struct radius_session *sess = timeout_ctx;
00241 
00242         RADIUS_DEBUG("Timing out authentication session 0x%x", sess->sess_id);
00243         radius_server_session_remove(data, sess);
00244 }
00245 
00246 
00247 static struct radius_session *
00248 radius_server_new_session(struct radius_server_data *data,
00249                           struct radius_client *client)
00250 {
00251         struct radius_session *sess;
00252 
00253         if (data->num_sess >= RADIUS_MAX_SESSION) {
00254                 RADIUS_DEBUG("Maximum number of existing session - no room "
00255                              "for a new session");
00256                 return NULL;
00257         }
00258 
00259         sess = os_zalloc(sizeof(*sess));
00260         if (sess == NULL)
00261                 return NULL;
00262 
00263         sess->server = data;
00264         sess->client = client;
00265         sess->sess_id = data->next_sess_id++;
00266         sess->next = client->sessions;
00267         client->sessions = sess;
00268         eloop_register_timeout(RADIUS_SESSION_TIMEOUT, 0,
00269                                radius_server_session_timeout, data, sess);
00270         data->num_sess++;
00271         return sess;
00272 }
00273 
00274 
00275 static struct radius_session *
00276 radius_server_get_new_session(struct radius_server_data *data,
00277                               struct radius_client *client,
00278                               struct radius_msg *msg)
00279 {
00280         u8 *user;
00281         size_t user_len;
00282         int res;
00283         struct radius_session *sess;
00284         struct eap_config eap_conf;
00285 
00286         RADIUS_DEBUG("Creating a new session");
00287 
00288         user = os_malloc(256);
00289         if (user == NULL) {
00290                 return NULL;
00291         }
00292         res = radius_msg_get_attr(msg, RADIUS_ATTR_USER_NAME, user, 256);
00293         if (res < 0 || res > 256) {
00294                 RADIUS_DEBUG("Could not get User-Name");
00295                 os_free(user);
00296                 return NULL;
00297         }
00298         user_len = res;
00299         RADIUS_DUMP_ASCII("User-Name", user, user_len);
00300 
00301         res = data->get_eap_user(data->conf_ctx, user, user_len, 0, NULL);
00302         os_free(user);
00303 
00304         if (res == 0) {
00305                 RADIUS_DEBUG("Matching user entry found");
00306                 sess = radius_server_new_session(data, client);
00307                 if (sess == NULL) {
00308                         RADIUS_DEBUG("Failed to create a new session");
00309                         return NULL;
00310                 }
00311         } else {
00312                 RADIUS_DEBUG("User-Name not found from user database");
00313                 return NULL;
00314         }
00315 
00316         os_memset(&eap_conf, 0, sizeof(eap_conf));
00317         eap_conf.ssl_ctx = data->ssl_ctx;
00318         eap_conf.eap_sim_db_priv = data->eap_sim_db_priv;
00319         eap_conf.backend_auth = TRUE;
00320         eap_conf.eap_server = 1;
00321         eap_conf.pac_opaque_encr_key = data->pac_opaque_encr_key;
00322         eap_conf.eap_fast_a_id = data->eap_fast_a_id;
00323         eap_conf.eap_fast_a_id_len = data->eap_fast_a_id_len;
00324         eap_conf.eap_fast_a_id_info = data->eap_fast_a_id_info;
00325         eap_conf.eap_fast_prov = data->eap_fast_prov;
00326         eap_conf.pac_key_lifetime = data->pac_key_lifetime;
00327         eap_conf.pac_key_refresh_time = data->pac_key_refresh_time;
00328         eap_conf.eap_sim_aka_result_ind = data->eap_sim_aka_result_ind;
00329         eap_conf.tnc = data->tnc;
00330         eap_conf.wps = data->wps;
00331         sess->eap = eap_server_sm_init(sess, &radius_server_eapol_cb,
00332                                        &eap_conf);
00333         if (sess->eap == NULL) {
00334                 RADIUS_DEBUG("Failed to initialize EAP state machine for the "
00335                              "new session");
00336                 radius_server_session_free(data, sess);
00337                 return NULL;
00338         }
00339         sess->eap_if = eap_get_interface(sess->eap);
00340         sess->eap_if->eapRestart = TRUE;
00341         sess->eap_if->portEnabled = TRUE;
00342 
00343         RADIUS_DEBUG("New session 0x%x initialized", sess->sess_id);
00344 
00345         return sess;
00346 }
00347 
00348 
00349 static struct radius_msg *
00350 radius_server_encapsulate_eap(struct radius_server_data *data,
00351                               struct radius_client *client,
00352                               struct radius_session *sess,
00353                               struct radius_msg *request)
00354 {
00355         struct radius_msg *msg;
00356         int code;
00357         unsigned int sess_id;
00358 
00359         if (sess->eap_if->eapFail) {
00360                 sess->eap_if->eapFail = FALSE;
00361                 code = RADIUS_CODE_ACCESS_REJECT;
00362         } else if (sess->eap_if->eapSuccess) {
00363                 sess->eap_if->eapSuccess = FALSE;
00364                 code = RADIUS_CODE_ACCESS_ACCEPT;
00365         } else {
00366                 sess->eap_if->eapReq = FALSE;
00367                 code = RADIUS_CODE_ACCESS_CHALLENGE;
00368         }
00369 
00370         msg = radius_msg_new(code, request->hdr->identifier);
00371         if (msg == NULL) {
00372                 RADIUS_DEBUG("Failed to allocate reply message");
00373                 return NULL;
00374         }
00375 
00376         sess_id = htonl(sess->sess_id);
00377         if (code == RADIUS_CODE_ACCESS_CHALLENGE &&
00378             !radius_msg_add_attr(msg, RADIUS_ATTR_STATE,
00379                                  (u8 *) &sess_id, sizeof(sess_id))) {
00380                 RADIUS_DEBUG("Failed to add State attribute");
00381         }
00382 
00383         if (sess->eap_if->eapReqData &&
00384             !radius_msg_add_eap(msg, wpabuf_head(sess->eap_if->eapReqData),
00385                                 wpabuf_len(sess->eap_if->eapReqData))) {
00386                 RADIUS_DEBUG("Failed to add EAP-Message attribute");
00387         }
00388 
00389         if (code == RADIUS_CODE_ACCESS_ACCEPT && sess->eap_if->eapKeyData) {
00390                 int len;
00391                 if (sess->eap_if->eapKeyDataLen > 64) {
00392                         len = 32;
00393                 } else {
00394                         len = sess->eap_if->eapKeyDataLen / 2;
00395                 }
00396                 if (!radius_msg_add_mppe_keys(msg, request->hdr->authenticator,
00397                                               (u8 *) client->shared_secret,
00398                                               client->shared_secret_len,
00399                                               sess->eap_if->eapKeyData + len,
00400                                               len, sess->eap_if->eapKeyData,
00401                                               len)) {
00402                         RADIUS_DEBUG("Failed to add MPPE key attributes");
00403                 }
00404         }
00405 
00406         if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
00407                 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
00408                 radius_msg_free(msg);
00409                 os_free(msg);
00410                 return NULL;
00411         }
00412 
00413         if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
00414                                   client->shared_secret_len,
00415                                   request->hdr->authenticator) < 0) {
00416                 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
00417         }
00418 
00419         return msg;
00420 }
00421 
00422 
00423 static int radius_server_reject(struct radius_server_data *data,
00424                                 struct radius_client *client,
00425                                 struct radius_msg *request,
00426                                 struct sockaddr *from, socklen_t fromlen,
00427                                 const char *from_addr, int from_port)
00428 {
00429         struct radius_msg *msg;
00430         int ret = 0;
00431         struct eap_hdr eapfail;
00432 
00433         RADIUS_DEBUG("Reject invalid request from %s:%d",
00434                      from_addr, from_port);
00435 
00436         msg = radius_msg_new(RADIUS_CODE_ACCESS_REJECT,
00437                              request->hdr->identifier);
00438         if (msg == NULL) {
00439                 return -1;
00440         }
00441 
00442         os_memset(&eapfail, 0, sizeof(eapfail));
00443         eapfail.code = EAP_CODE_FAILURE;
00444         eapfail.identifier = 0;
00445         eapfail.length = host_to_be16(sizeof(eapfail));
00446 
00447         if (!radius_msg_add_eap(msg, (u8 *) &eapfail, sizeof(eapfail))) {
00448                 RADIUS_DEBUG("Failed to add EAP-Message attribute");
00449         }
00450 
00451         if (radius_msg_copy_attr(msg, request, RADIUS_ATTR_PROXY_STATE) < 0) {
00452                 RADIUS_DEBUG("Failed to copy Proxy-State attribute(s)");
00453                 radius_msg_free(msg);
00454                 os_free(msg);
00455                 return -1;
00456         }
00457 
00458         if (radius_msg_finish_srv(msg, (u8 *) client->shared_secret,
00459                                   client->shared_secret_len,
00460                                   request->hdr->authenticator) < 0) {
00461                 RADIUS_DEBUG("Failed to add Message-Authenticator attribute");
00462         }
00463 
00464         if (wpa_debug_level <= MSG_MSGDUMP) {
00465                 radius_msg_dump(msg);
00466         }
00467 
00468         data->counters.access_rejects++;
00469         client->counters.access_rejects++;
00470         if (sendto(data->auth_sock, msg->buf, msg->buf_used, 0,
00471                    (struct sockaddr *) from, sizeof(*from)) < 0) {
00472                 perror("sendto[RADIUS SRV]");
00473                 ret = -1;
00474         }
00475 
00476         radius_msg_free(msg);
00477         os_free(msg);
00478 
00479         return ret;
00480 }
00481 
00482 
00483 static int radius_server_request(struct radius_server_data *data,
00484                                  struct radius_msg *msg,
00485                                  struct sockaddr *from, socklen_t fromlen,
00486                                  struct radius_client *client,
00487                                  const char *from_addr, int from_port,
00488                                  struct radius_session *force_sess)
00489 {
00490         u8 *eap = NULL;
00491         size_t eap_len;
00492         int res, state_included = 0;
00493         u8 statebuf[4];
00494         unsigned int state;
00495         struct radius_session *sess;
00496         struct radius_msg *reply;
00497         int is_complete = 0;
00498 
00499         if (force_sess)
00500                 sess = force_sess;
00501         else {
00502                 res = radius_msg_get_attr(msg, RADIUS_ATTR_STATE, statebuf,
00503                                           sizeof(statebuf));
00504                 state_included = res >= 0;
00505                 if (res == sizeof(statebuf)) {
00506                         state = WPA_GET_BE32(statebuf);
00507                         sess = radius_server_get_session(client, state);
00508                 } else {
00509                         sess = NULL;
00510                 }
00511         }
00512 
00513         if (sess) {
00514                 RADIUS_DEBUG("Request for session 0x%x", sess->sess_id);
00515         } else if (state_included) {
00516                 RADIUS_DEBUG("State attribute included but no session found");
00517                 radius_server_reject(data, client, msg, from, fromlen,
00518                                      from_addr, from_port);
00519                 return -1;
00520         } else {
00521                 sess = radius_server_get_new_session(data, client, msg);
00522                 if (sess == NULL) {
00523                         RADIUS_DEBUG("Could not create a new session");
00524                         radius_server_reject(data, client, msg, from, fromlen,
00525                                              from_addr, from_port);
00526                         return -1;
00527                 }
00528         }
00529 
00530         if (sess->last_from_port == from_port &&
00531             sess->last_identifier == msg->hdr->identifier &&
00532             os_memcmp(sess->last_authenticator, msg->hdr->authenticator, 16) ==
00533             0) {
00534                 RADIUS_DEBUG("Duplicate message from %s", from_addr);
00535                 data->counters.dup_access_requests++;
00536                 client->counters.dup_access_requests++;
00537 
00538                 if (sess->last_reply) {
00539                         res = sendto(data->auth_sock, sess->last_reply->buf,
00540                                      sess->last_reply->buf_used, 0,
00541                                      (struct sockaddr *) from, fromlen);
00542                         if (res < 0) {
00543                                 perror("sendto[RADIUS SRV]");
00544                         }
00545                         return 0;
00546                 }
00547 
00548                 RADIUS_DEBUG("No previous reply available for duplicate "
00549                              "message");
00550                 return -1;
00551         }
00552                       
00553         eap = radius_msg_get_eap(msg, &eap_len);
00554         if (eap == NULL) {
00555                 RADIUS_DEBUG("No EAP-Message in RADIUS packet from %s",
00556                              from_addr);
00557                 data->counters.packets_dropped++;
00558                 client->counters.packets_dropped++;
00559                 return -1;
00560         }
00561 
00562         RADIUS_DUMP("Received EAP data", eap, eap_len);
00563 
00564         /* FIX: if Code is Request, Success, or Failure, send Access-Reject;
00565          * RFC3579 Sect. 2.6.2.
00566          * Include EAP-Response/Nak with no preferred method if
00567          * code == request.
00568          * If code is not 1-4, discard the packet silently.
00569          * Or is this already done by the EAP state machine? */
00570 
00571         wpabuf_free(sess->eap_if->eapRespData);
00572         sess->eap_if->eapRespData = wpabuf_alloc_ext_data(eap, eap_len);
00573         if (sess->eap_if->eapRespData == NULL)
00574                 os_free(eap);
00575         eap = NULL;
00576         sess->eap_if->eapResp = TRUE;
00577         eap_server_sm_step(sess->eap);
00578 
00579         if ((sess->eap_if->eapReq || sess->eap_if->eapSuccess ||
00580              sess->eap_if->eapFail) && sess->eap_if->eapReqData) {
00581                 RADIUS_DUMP("EAP data from the state machine",
00582                             wpabuf_head(sess->eap_if->eapReqData),
00583                             wpabuf_len(sess->eap_if->eapReqData));
00584         } else if (sess->eap_if->eapFail) {
00585                 RADIUS_DEBUG("No EAP data from the state machine, but eapFail "
00586                              "set");
00587         } else if (eap_sm_method_pending(sess->eap)) {
00588                 if (sess->last_msg) {
00589                         radius_msg_free(sess->last_msg);
00590                         os_free(sess->last_msg);
00591                 }
00592                 sess->last_msg = msg;
00593                 sess->last_from_port = from_port;
00594                 os_free(sess->last_from_addr);
00595                 sess->last_from_addr = os_strdup(from_addr);
00596                 sess->last_fromlen = fromlen;
00597                 os_memcpy(&sess->last_from, from, fromlen);
00598                 return -2;
00599         } else {
00600                 RADIUS_DEBUG("No EAP data from the state machine - ignore this"
00601                              " Access-Request silently (assuming it was a "
00602                              "duplicate)");
00603                 data->counters.packets_dropped++;
00604                 client->counters.packets_dropped++;
00605                 return -1;
00606         }
00607 
00608         if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
00609                 is_complete = 1;
00610 
00611         reply = radius_server_encapsulate_eap(data, client, sess, msg);
00612 
00613         if (reply) {
00614                 RADIUS_DEBUG("Reply to %s:%d", from_addr, from_port);
00615                 if (wpa_debug_level <= MSG_MSGDUMP) {
00616                         radius_msg_dump(reply);
00617                 }
00618 
00619                 switch (reply->hdr->code) {
00620                 case RADIUS_CODE_ACCESS_ACCEPT:
00621                         data->counters.access_accepts++;
00622                         client->counters.access_accepts++;
00623                         break;
00624                 case RADIUS_CODE_ACCESS_REJECT:
00625                         data->counters.access_rejects++;
00626                         client->counters.access_rejects++;
00627                         break;
00628                 case RADIUS_CODE_ACCESS_CHALLENGE:
00629                         data->counters.access_challenges++;
00630                         client->counters.access_challenges++;
00631                         break;
00632                 }
00633                 res = sendto(data->auth_sock, reply->buf, reply->buf_used, 0,
00634                              (struct sockaddr *) from, fromlen);
00635                 if (res < 0) {
00636                         perror("sendto[RADIUS SRV]");
00637                 }
00638                 if (sess->last_reply) {
00639                         radius_msg_free(sess->last_reply);
00640                         os_free(sess->last_reply);
00641                 }
00642                 sess->last_reply = reply;
00643                 sess->last_from_port = from_port;
00644                 sess->last_identifier = msg->hdr->identifier;
00645                 os_memcpy(sess->last_authenticator, msg->hdr->authenticator,
00646                           16);
00647         } else {
00648                 data->counters.packets_dropped++;
00649                 client->counters.packets_dropped++;
00650         }
00651 
00652         if (is_complete) {
00653                 RADIUS_DEBUG("Removing completed session 0x%x after timeout",
00654                              sess->sess_id);
00655                 eloop_cancel_timeout(radius_server_session_remove_timeout,
00656                                      data, sess);
00657                 eloop_register_timeout(10, 0,
00658                                        radius_server_session_remove_timeout,
00659                                        data, sess);
00660         }
00661 
00662         return 0;
00663 }
00664 
00665 
00666 static void radius_server_receive_auth(int sock, void *eloop_ctx,
00667                                        void *sock_ctx)
00668 {
00669         struct radius_server_data *data = eloop_ctx;
00670         u8 *buf = NULL;
00671         union {
00672                 struct sockaddr_storage ss;
00673                 struct sockaddr_in sin;
00674 #ifdef CONFIG_IPV6
00675                 struct sockaddr_in6 sin6;
00676 #endif /* CONFIG_IPV6 */
00677         } from;
00678         socklen_t fromlen;
00679         int len;
00680         struct radius_client *client = NULL;
00681         struct radius_msg *msg = NULL;
00682         char abuf[50];
00683         int from_port = 0;
00684 
00685         buf = os_malloc(RADIUS_MAX_MSG_LEN);
00686         if (buf == NULL) {
00687                 goto fail;
00688         }
00689 
00690         fromlen = sizeof(from);
00691         len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
00692                        (struct sockaddr *) &from.ss, &fromlen);
00693         if (len < 0) {
00694                 perror("recvfrom[radius_server]");
00695                 goto fail;
00696         }
00697 
00698 #ifdef CONFIG_IPV6
00699         if (data->ipv6) {
00700                 if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
00701                               sizeof(abuf)) == NULL)
00702                         abuf[0] = '\0';
00703                 from_port = ntohs(from.sin6.sin6_port);
00704                 RADIUS_DEBUG("Received %d bytes from %s:%d",
00705                              len, abuf, from_port);
00706 
00707                 client = radius_server_get_client(data,
00708                                                   (struct in_addr *)
00709                                                   &from.sin6.sin6_addr, 1);
00710         }
00711 #endif /* CONFIG_IPV6 */
00712 
00713         if (!data->ipv6) {
00714                 os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
00715                 from_port = ntohs(from.sin.sin_port);
00716                 RADIUS_DEBUG("Received %d bytes from %s:%d",
00717                              len, abuf, from_port);
00718 
00719                 client = radius_server_get_client(data, &from.sin.sin_addr, 0);
00720         }
00721 
00722         RADIUS_DUMP("Received data", buf, len);
00723 
00724         if (client == NULL) {
00725                 RADIUS_DEBUG("Unknown client %s - packet ignored", abuf);
00726                 data->counters.invalid_requests++;
00727                 goto fail;
00728         }
00729 
00730         msg = radius_msg_parse(buf, len);
00731         if (msg == NULL) {
00732                 RADIUS_DEBUG("Parsing incoming RADIUS frame failed");
00733                 data->counters.malformed_access_requests++;
00734                 client->counters.malformed_access_requests++;
00735                 goto fail;
00736         }
00737 
00738         os_free(buf);
00739         buf = NULL;
00740 
00741         if (wpa_debug_level <= MSG_MSGDUMP) {
00742                 radius_msg_dump(msg);
00743         }
00744 
00745         if (msg->hdr->code != RADIUS_CODE_ACCESS_REQUEST) {
00746                 RADIUS_DEBUG("Unexpected RADIUS code %d", msg->hdr->code);
00747                 data->counters.unknown_types++;
00748                 client->counters.unknown_types++;
00749                 goto fail;
00750         }
00751 
00752         data->counters.access_requests++;
00753         client->counters.access_requests++;
00754 
00755         if (radius_msg_verify_msg_auth(msg, (u8 *) client->shared_secret,
00756                                        client->shared_secret_len, NULL)) {
00757                 RADIUS_DEBUG("Invalid Message-Authenticator from %s", abuf);
00758                 data->counters.bad_authenticators++;
00759                 client->counters.bad_authenticators++;
00760                 goto fail;
00761         }
00762 
00763         if (radius_server_request(data, msg, (struct sockaddr *) &from,
00764                                   fromlen, client, abuf, from_port, NULL) ==
00765             -2)
00766                 return; /* msg was stored with the session */
00767 
00768 fail:
00769         if (msg) {
00770                 radius_msg_free(msg);
00771                 os_free(msg);
00772         }
00773         os_free(buf);
00774 }
00775 
00776 
00777 static int radius_server_disable_pmtu_discovery(int s)
00778 {
00779         int r = -1;
00780 #if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
00781         /* Turn off Path MTU discovery on IPv4/UDP sockets. */
00782         int action = IP_PMTUDISC_DONT;
00783         r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
00784                        sizeof(action));
00785         if (r == -1)
00786                 wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
00787                            "%s", strerror(errno));
00788 #endif
00789         return r;
00790 }
00791 
00792 
00793 static int radius_server_open_socket(int port)
00794 {
00795         int s;
00796         struct sockaddr_in addr;
00797 
00798         s = socket(PF_INET, SOCK_DGRAM, 0);
00799         if (s < 0) {
00800                 perror("socket");
00801                 return -1;
00802         }
00803 
00804         radius_server_disable_pmtu_discovery(s);
00805 
00806         os_memset(&addr, 0, sizeof(addr));
00807         addr.sin_family = AF_INET;
00808         addr.sin_port = htons(port);
00809         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00810                 perror("bind");
00811                 close(s);
00812                 return -1;
00813         }
00814 
00815         return s;
00816 }
00817 
00818 
00819 #ifdef CONFIG_IPV6
00820 static int radius_server_open_socket6(int port)
00821 {
00822         int s;
00823         struct sockaddr_in6 addr;
00824 
00825         s = socket(PF_INET6, SOCK_DGRAM, 0);
00826         if (s < 0) {
00827                 perror("socket[IPv6]");
00828                 return -1;
00829         }
00830 
00831         os_memset(&addr, 0, sizeof(addr));
00832         addr.sin6_family = AF_INET6;
00833         os_memcpy(&addr.sin6_addr, &in6addr_any, sizeof(in6addr_any));
00834         addr.sin6_port = htons(port);
00835         if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
00836                 perror("bind");
00837                 close(s);
00838                 return -1;
00839         }
00840 
00841         return s;
00842 }
00843 #endif /* CONFIG_IPV6 */
00844 
00845 
00846 static void radius_server_free_sessions(struct radius_server_data *data,
00847                                         struct radius_session *sessions)
00848 {
00849         struct radius_session *session, *prev;
00850 
00851         session = sessions;
00852         while (session) {
00853                 prev = session;
00854                 session = session->next;
00855                 radius_server_session_free(data, prev);
00856         }
00857 }
00858 
00859 
00860 static void radius_server_free_clients(struct radius_server_data *data,
00861                                        struct radius_client *clients)
00862 {
00863         struct radius_client *client, *prev;
00864 
00865         client = clients;
00866         while (client) {
00867                 prev = client;
00868                 client = client->next;
00869 
00870                 radius_server_free_sessions(data, prev->sessions);
00871                 os_free(prev->shared_secret);
00872                 os_free(prev);
00873         }
00874 }
00875 
00876 
00877 static struct radius_client *
00878 radius_server_read_clients(const char *client_file, int ipv6)
00879 {
00880         FILE *f;
00881         const int buf_size = 1024;
00882         char *buf, *pos;
00883         struct radius_client *clients, *tail, *entry;
00884         int line = 0, mask, failed = 0, i;
00885         struct in_addr addr;
00886 #ifdef CONFIG_IPV6
00887         struct in6_addr addr6;
00888 #endif /* CONFIG_IPV6 */
00889         unsigned int val;
00890 
00891         f = fopen(client_file, "r");
00892         if (f == NULL) {
00893                 RADIUS_ERROR("Could not open client file '%s'", client_file);
00894                 return NULL;
00895         }
00896 
00897         buf = os_malloc(buf_size);
00898         if (buf == NULL) {
00899                 fclose(f);
00900                 return NULL;
00901         }
00902 
00903         clients = tail = NULL;
00904         while (fgets(buf, buf_size, f)) {
00905                 /* Configuration file format:
00906                  * 192.168.1.0/24 secret
00907                  * 192.168.1.2 secret
00908                  * fe80::211:22ff:fe33:4455/64 secretipv6
00909                  */
00910                 line++;
00911                 buf[buf_size - 1] = '\0';
00912                 pos = buf;
00913                 while (*pos != '\0' && *pos != '\n')
00914                         pos++;
00915                 if (*pos == '\n')
00916                         *pos = '\0';
00917                 if (*buf == '\0' || *buf == '#')
00918                         continue;
00919 
00920                 pos = buf;
00921                 while ((*pos >= '0' && *pos <= '9') || *pos == '.' ||
00922                        (*pos >= 'a' && *pos <= 'f') || *pos == ':' ||
00923                        (*pos >= 'A' && *pos <= 'F')) {
00924                         pos++;
00925                 }
00926 
00927                 if (*pos == '\0') {
00928                         failed = 1;
00929                         break;
00930                 }
00931 
00932                 if (*pos == '/') {
00933                         char *end;
00934                         *pos++ = '\0';
00935                         mask = strtol(pos, &end, 10);
00936                         if ((pos == end) ||
00937                             (mask < 0 || mask > (ipv6 ? 128 : 32))) {
00938                                 failed = 1;
00939                                 break;
00940                         }
00941                         pos = end;
00942                 } else {
00943                         mask = ipv6 ? 128 : 32;
00944                         *pos++ = '\0';
00945                 }
00946 
00947                 if (!ipv6 && inet_aton(buf, &addr) == 0) {
00948                         failed = 1;
00949                         break;
00950                 }
00951 #ifdef CONFIG_IPV6
00952                 if (ipv6 && inet_pton(AF_INET6, buf, &addr6) <= 0) {
00953                         if (inet_pton(AF_INET, buf, &addr) <= 0) {
00954                                 failed = 1;
00955                                 break;
00956                         }
00957                         /* Convert IPv4 address to IPv6 */
00958                         if (mask <= 32)
00959                                 mask += (128 - 32);
00960                         os_memset(addr6.s6_addr, 0, 10);
00961                         addr6.s6_addr[10] = 0xff;
00962                         addr6.s6_addr[11] = 0xff;
00963                         os_memcpy(addr6.s6_addr + 12, (char *) &addr.s_addr,
00964                                   4);
00965                 }
00966 #endif /* CONFIG_IPV6 */
00967 
00968                 while (*pos == ' ' || *pos == '\t') {
00969                         pos++;
00970                 }
00971 
00972                 if (*pos == '\0') {
00973                         failed = 1;
00974                         break;
00975                 }
00976 
00977                 entry = os_zalloc(sizeof(*entry));
00978                 if (entry == NULL) {
00979                         failed = 1;
00980                         break;
00981                 }
00982                 entry->shared_secret = os_strdup(pos);
00983                 if (entry->shared_secret == NULL) {
00984                         failed = 1;
00985                         os_free(entry);
00986                         break;
00987                 }
00988                 entry->shared_secret_len = os_strlen(entry->shared_secret);
00989                 entry->addr.s_addr = addr.s_addr;
00990                 if (!ipv6) {
00991                         val = 0;
00992                         for (i = 0; i < mask; i++)
00993                                 val |= 1 << (31 - i);
00994                         entry->mask.s_addr = htonl(val);
00995                 }
00996 #ifdef CONFIG_IPV6
00997                 if (ipv6) {
00998                         int offset = mask / 8;
00999 
01000                         os_memcpy(entry->addr6.s6_addr, addr6.s6_addr, 16);
01001                         os_memset(entry->mask6.s6_addr, 0xff, offset);
01002                         val = 0;
01003                         for (i = 0; i < (mask % 8); i++)
01004                                 val |= 1 << (7 - i);
01005                         if (offset < 16)
01006                                 entry->mask6.s6_addr[offset] = val;
01007                 }
01008 #endif /* CONFIG_IPV6 */
01009 
01010                 if (tail == NULL) {
01011                         clients = tail = entry;
01012                 } else {
01013                         tail->next = entry;
01014                         tail = entry;
01015                 }
01016         }
01017 
01018         if (failed) {
01019                 RADIUS_ERROR("Invalid line %d in '%s'", line, client_file);
01020                 radius_server_free_clients(NULL, clients);
01021                 clients = NULL;
01022         }
01023 
01024         os_free(buf);
01025         fclose(f);
01026 
01027         return clients;
01028 }
01029 
01030 
01031 struct radius_server_data *
01032 radius_server_init(struct radius_server_conf *conf)
01033 {
01034         struct radius_server_data *data;
01035 
01036 #ifndef CONFIG_IPV6
01037         if (conf->ipv6) {
01038                 fprintf(stderr, "RADIUS server compiled without IPv6 "
01039                         "support.\n");
01040                 return NULL;
01041         }
01042 #endif /* CONFIG_IPV6 */
01043 
01044         data = os_zalloc(sizeof(*data));
01045         if (data == NULL)
01046                 return NULL;
01047 
01048         os_get_time(&data->start_time);
01049         data->conf_ctx = conf->conf_ctx;
01050         data->eap_sim_db_priv = conf->eap_sim_db_priv;
01051         data->ssl_ctx = conf->ssl_ctx;
01052         data->ipv6 = conf->ipv6;
01053         if (conf->pac_opaque_encr_key) {
01054                 data->pac_opaque_encr_key = os_malloc(16);
01055                 os_memcpy(data->pac_opaque_encr_key, conf->pac_opaque_encr_key,
01056                           16);
01057         }
01058         if (conf->eap_fast_a_id) {
01059                 data->eap_fast_a_id = os_malloc(conf->eap_fast_a_id_len);
01060                 if (data->eap_fast_a_id) {
01061                         os_memcpy(data->eap_fast_a_id, conf->eap_fast_a_id,
01062                                   conf->eap_fast_a_id_len);
01063                         data->eap_fast_a_id_len = conf->eap_fast_a_id_len;
01064                 }
01065         }
01066         if (conf->eap_fast_a_id_info)
01067                 data->eap_fast_a_id_info = os_strdup(conf->eap_fast_a_id_info);
01068         data->eap_fast_prov = conf->eap_fast_prov;
01069         data->pac_key_lifetime = conf->pac_key_lifetime;
01070         data->pac_key_refresh_time = conf->pac_key_refresh_time;
01071         data->get_eap_user = conf->get_eap_user;
01072         data->eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
01073         data->tnc = conf->tnc;
01074         data->wps = conf->wps;
01075         if (conf->eap_req_id_text) {
01076                 data->eap_req_id_text = os_malloc(conf->eap_req_id_text_len);
01077                 if (data->eap_req_id_text) {
01078                         os_memcpy(data->eap_req_id_text, conf->eap_req_id_text,
01079                                   conf->eap_req_id_text_len);
01080                         data->eap_req_id_text_len = conf->eap_req_id_text_len;
01081                 }
01082         }
01083 
01084         data->clients = radius_server_read_clients(conf->client_file,
01085                                                    conf->ipv6);
01086         if (data->clients == NULL) {
01087                 printf("No RADIUS clients configured.\n");
01088                 radius_server_deinit(data);
01089                 return NULL;
01090         }
01091 
01092 #ifdef CONFIG_IPV6
01093         if (conf->ipv6)
01094                 data->auth_sock = radius_server_open_socket6(conf->auth_port);
01095         else
01096 #endif /* CONFIG_IPV6 */
01097         data->auth_sock = radius_server_open_socket(conf->auth_port);
01098         if (data->auth_sock < 0) {
01099                 printf("Failed to open UDP socket for RADIUS authentication "
01100                        "server\n");
01101                 radius_server_deinit(data);
01102                 return NULL;
01103         }
01104         if (eloop_register_read_sock(data->auth_sock,
01105                                      radius_server_receive_auth,
01106                                      data, NULL)) {
01107                 radius_server_deinit(data);
01108                 return NULL;
01109         }
01110 
01111         return data;
01112 }
01113 
01114 
01115 void radius_server_deinit(struct radius_server_data *data)
01116 {
01117         if (data == NULL)
01118                 return;
01119 
01120         if (data->auth_sock >= 0) {
01121                 eloop_unregister_read_sock(data->auth_sock);
01122                 close(data->auth_sock);
01123         }
01124 
01125         radius_server_free_clients(data, data->clients);
01126 
01127         os_free(data->pac_opaque_encr_key);
01128         os_free(data->eap_fast_a_id);
01129         os_free(data->eap_fast_a_id_info);
01130         os_free(data->eap_req_id_text);
01131         os_free(data);
01132 }
01133 
01134 
01135 int radius_server_get_mib(struct radius_server_data *data, char *buf,
01136                           size_t buflen)
01137 {
01138         int ret, uptime;
01139         unsigned int idx;
01140         char *end, *pos;
01141         struct os_time now;
01142         struct radius_client *cli;
01143 
01144         /* RFC 2619 - RADIUS Authentication Server MIB */
01145 
01146         if (data == NULL || buflen == 0)
01147                 return 0;
01148 
01149         pos = buf;
01150         end = buf + buflen;
01151 
01152         os_get_time(&now);
01153         uptime = (now.sec - data->start_time.sec) * 100 +
01154                 ((now.usec - data->start_time.usec) / 10000) % 100;
01155         ret = os_snprintf(pos, end - pos,
01156                           "RADIUS-AUTH-SERVER-MIB\n"
01157                           "radiusAuthServIdent=hostapd\n"
01158                           "radiusAuthServUpTime=%d\n"
01159                           "radiusAuthServResetTime=0\n"
01160                           "radiusAuthServConfigReset=4\n",
01161                           uptime);
01162         if (ret < 0 || ret >= end - pos) {
01163                 *pos = '\0';
01164                 return pos - buf;
01165         }
01166         pos += ret;
01167 
01168         ret = os_snprintf(pos, end - pos,
01169                           "radiusAuthServTotalAccessRequests=%u\n"
01170                           "radiusAuthServTotalInvalidRequests=%u\n"
01171                           "radiusAuthServTotalDupAccessRequests=%u\n"
01172                           "radiusAuthServTotalAccessAccepts=%u\n"
01173                           "radiusAuthServTotalAccessRejects=%u\n"
01174                           "radiusAuthServTotalAccessChallenges=%u\n"
01175                           "radiusAuthServTotalMalformedAccessRequests=%u\n"
01176                           "radiusAuthServTotalBadAuthenticators=%u\n"
01177                           "radiusAuthServTotalPacketsDropped=%u\n"
01178                           "radiusAuthServTotalUnknownTypes=%u\n",
01179                           data->counters.access_requests,
01180                           data->counters.invalid_requests,
01181                           data->counters.dup_access_requests,
01182                           data->counters.access_accepts,
01183                           data->counters.access_rejects,
01184                           data->counters.access_challenges,
01185                           data->counters.malformed_access_requests,
01186                           data->counters.bad_authenticators,
01187                           data->counters.packets_dropped,
01188                           data->counters.unknown_types);
01189         if (ret < 0 || ret >= end - pos) {
01190                 *pos = '\0';
01191                 return pos - buf;
01192         }
01193         pos += ret;
01194 
01195         for (cli = data->clients, idx = 0; cli; cli = cli->next, idx++) {
01196                 char abuf[50], mbuf[50];
01197 #ifdef CONFIG_IPV6
01198                 if (data->ipv6) {
01199                         if (inet_ntop(AF_INET6, &cli->addr6, abuf,
01200                                       sizeof(abuf)) == NULL)
01201                                 abuf[0] = '\0';
01202                         if (inet_ntop(AF_INET6, &cli->mask6, abuf,
01203                                       sizeof(mbuf)) == NULL)
01204                                 mbuf[0] = '\0';
01205                 }
01206 #endif /* CONFIG_IPV6 */
01207                 if (!data->ipv6) {
01208                         os_strlcpy(abuf, inet_ntoa(cli->addr), sizeof(abuf));
01209                         os_strlcpy(mbuf, inet_ntoa(cli->mask), sizeof(mbuf));
01210                 }
01211 
01212                 ret = os_snprintf(pos, end - pos,
01213                                   "radiusAuthClientIndex=%u\n"
01214                                   "radiusAuthClientAddress=%s/%s\n"
01215                                   "radiusAuthServAccessRequests=%u\n"
01216                                   "radiusAuthServDupAccessRequests=%u\n"
01217                                   "radiusAuthServAccessAccepts=%u\n"
01218                                   "radiusAuthServAccessRejects=%u\n"
01219                                   "radiusAuthServAccessChallenges=%u\n"
01220                                   "radiusAuthServMalformedAccessRequests=%u\n"
01221                                   "radiusAuthServBadAuthenticators=%u\n"
01222                                   "radiusAuthServPacketsDropped=%u\n"
01223                                   "radiusAuthServUnknownTypes=%u\n",
01224                                   idx,
01225                                   abuf, mbuf,
01226                                   cli->counters.access_requests,
01227                                   cli->counters.dup_access_requests,
01228                                   cli->counters.access_accepts,
01229                                   cli->counters.access_rejects,
01230                                   cli->counters.access_challenges,
01231                                   cli->counters.malformed_access_requests,
01232                                   cli->counters.bad_authenticators,
01233                                   cli->counters.packets_dropped,
01234                                   cli->counters.unknown_types);
01235                 if (ret < 0 || ret >= end - pos) {
01236                         *pos = '\0';
01237                         return pos - buf;
01238                 }
01239                 pos += ret;
01240         }
01241 
01242         return pos - buf;
01243 }
01244 
01245 
01246 static int radius_server_get_eap_user(void *ctx, const u8 *identity,
01247                                       size_t identity_len, int phase2,
01248                                       struct eap_user *user)
01249 {
01250         struct radius_session *sess = ctx;
01251         struct radius_server_data *data = sess->server;
01252 
01253         return data->get_eap_user(data->conf_ctx, identity, identity_len,
01254                                   phase2, user);
01255 }
01256 
01257 
01258 static const char * radius_server_get_eap_req_id_text(void *ctx, size_t *len)
01259 {
01260         struct radius_session *sess = ctx;
01261         struct radius_server_data *data = sess->server;
01262         *len = data->eap_req_id_text_len;
01263         return data->eap_req_id_text;
01264 }
01265 
01266 
01267 static struct eapol_callbacks radius_server_eapol_cb =
01268 {
01269         .get_eap_user = radius_server_get_eap_user,
01270         .get_eap_req_id_text = radius_server_get_eap_req_id_text,
01271 };
01272 
01273 
01274 void radius_server_eap_pending_cb(struct radius_server_data *data, void *ctx)
01275 {
01276         struct radius_client *cli;
01277         struct radius_session *s, *sess = NULL;
01278         struct radius_msg *msg;
01279 
01280         if (data == NULL)
01281                 return;
01282 
01283         for (cli = data->clients; cli; cli = cli->next) {
01284                 for (s = cli->sessions; s; s = s->next) {
01285                         if (s->eap == ctx && s->last_msg) {
01286                                 sess = s;
01287                                 break;
01288                         }
01289                         if (sess)
01290                                 break;
01291                 }
01292                 if (sess)
01293                         break;
01294         }
01295 
01296         if (sess == NULL) {
01297                 RADIUS_DEBUG("No session matched callback ctx");
01298                 return;
01299         }
01300 
01301         msg = sess->last_msg;
01302         sess->last_msg = NULL;
01303         eap_sm_pending_cb(sess->eap);
01304         if (radius_server_request(data, msg,
01305                                   (struct sockaddr *) &sess->last_from,
01306                                   sess->last_fromlen, cli,
01307                                   sess->last_from_addr,
01308                                   sess->last_from_port, sess) == -2)
01309                 return; /* msg was stored with the session */
01310 
01311         radius_msg_free(msg);
01312         os_free(msg);
01313 }
01314 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on Sat Nov 21 23:16:52 2009 for hostapd by  doxygen 1.6.1