eap_server_tnc.c
Go to the documentation of this file.
00001 /*
00002  * EAP server method: EAP-TNC (Trusted Network Connect)
00003  * Copyright (c) 2007-2010, 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 "base64.h"
00019 #include "eap_i.h"
00020 #include "tncs.h"
00021 
00022 
00023 struct eap_tnc_data {
00024         enum eap_tnc_state {
00025                 START, CONTINUE, RECOMMENDATION, FRAG_ACK, WAIT_FRAG_ACK, DONE,
00026                 FAIL
00027         } state;
00028         enum { ALLOW, ISOLATE, NO_ACCESS, NO_RECOMMENDATION } recommendation;
00029         struct tncs_data *tncs;
00030         struct wpabuf *in_buf;
00031         struct wpabuf *out_buf;
00032         size_t out_used;
00033         size_t fragment_size;
00034         unsigned int was_done:1;
00035         unsigned int was_fail:1;
00036 };
00037 
00038 
00039 /* EAP-TNC Flags */
00040 #define EAP_TNC_FLAGS_LENGTH_INCLUDED 0x80
00041 #define EAP_TNC_FLAGS_MORE_FRAGMENTS 0x40
00042 #define EAP_TNC_FLAGS_START 0x20
00043 #define EAP_TNC_VERSION_MASK 0x07
00044 
00045 #define EAP_TNC_VERSION 1
00046 
00047 
00048 static const char * eap_tnc_state_txt(enum eap_tnc_state state)
00049 {
00050         switch (state) {
00051         case START:
00052                 return "START";
00053         case CONTINUE:
00054                 return "CONTINUE";
00055         case RECOMMENDATION:
00056                 return "RECOMMENDATION";
00057         case FRAG_ACK:
00058                 return "FRAG_ACK";
00059         case WAIT_FRAG_ACK:
00060                 return "WAIT_FRAG_ACK";
00061         case DONE:
00062                 return "DONE";
00063         case FAIL:
00064                 return "FAIL";
00065         }
00066         return "??";
00067 }
00068 
00069 
00070 static void eap_tnc_set_state(struct eap_tnc_data *data,
00071                               enum eap_tnc_state new_state)
00072 {
00073         wpa_printf(MSG_DEBUG, "EAP-TNC: %s -> %s",
00074                    eap_tnc_state_txt(data->state),
00075                    eap_tnc_state_txt(new_state));
00076         data->state = new_state;
00077 }
00078 
00079 
00080 static void * eap_tnc_init(struct eap_sm *sm)
00081 {
00082         struct eap_tnc_data *data;
00083 
00084         data = os_zalloc(sizeof(*data));
00085         if (data == NULL)
00086                 return NULL;
00087         eap_tnc_set_state(data, START);
00088         data->tncs = tncs_init();
00089         if (data->tncs == NULL) {
00090                 os_free(data);
00091                 return NULL;
00092         }
00093 
00094         data->fragment_size = 1300;
00095 
00096         return data;
00097 }
00098 
00099 
00100 static void eap_tnc_reset(struct eap_sm *sm, void *priv)
00101 {
00102         struct eap_tnc_data *data = priv;
00103         wpabuf_free(data->in_buf);
00104         wpabuf_free(data->out_buf);
00105         tncs_deinit(data->tncs);
00106         os_free(data);
00107 }
00108 
00109 
00110 static struct wpabuf * eap_tnc_build_start(struct eap_sm *sm,
00111                                            struct eap_tnc_data *data, u8 id)
00112 {
00113         struct wpabuf *req;
00114 
00115         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, EAP_CODE_REQUEST,
00116                             id);
00117         if (req == NULL) {
00118                 wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory for "
00119                            "request");
00120                 eap_tnc_set_state(data, FAIL);
00121                 return NULL;
00122         }
00123 
00124         wpabuf_put_u8(req, EAP_TNC_FLAGS_START | EAP_TNC_VERSION);
00125 
00126         eap_tnc_set_state(data, CONTINUE);
00127 
00128         return req;
00129 }
00130 
00131 
00132 static struct wpabuf * eap_tnc_build(struct eap_sm *sm,
00133                                      struct eap_tnc_data *data)
00134 {
00135         struct wpabuf *req;
00136         u8 *rpos, *rpos1;
00137         size_t rlen;
00138         char *start_buf, *end_buf;
00139         size_t start_len, end_len;
00140         size_t imv_len;
00141 
00142         imv_len = tncs_total_send_len(data->tncs);
00143 
00144         start_buf = tncs_if_tnccs_start(data->tncs);
00145         if (start_buf == NULL)
00146                 return NULL;
00147         start_len = os_strlen(start_buf);
00148         end_buf = tncs_if_tnccs_end();
00149         if (end_buf == NULL) {
00150                 os_free(start_buf);
00151                 return NULL;
00152         }
00153         end_len = os_strlen(end_buf);
00154 
00155         rlen = start_len + imv_len + end_len;
00156         req = wpabuf_alloc(rlen);
00157         if (req == NULL) {
00158                 os_free(start_buf);
00159                 os_free(end_buf);
00160                 return NULL;
00161         }
00162 
00163         wpabuf_put_data(req, start_buf, start_len);
00164         os_free(start_buf);
00165 
00166         rpos1 = wpabuf_put(req, 0);
00167         rpos = tncs_copy_send_buf(data->tncs, rpos1);
00168         wpabuf_put(req, rpos - rpos1);
00169 
00170         wpabuf_put_data(req, end_buf, end_len);
00171         os_free(end_buf);
00172 
00173         wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Request",
00174                           wpabuf_head(req), wpabuf_len(req));
00175 
00176         return req;
00177 }
00178 
00179 
00180 static struct wpabuf * eap_tnc_build_recommendation(struct eap_sm *sm,
00181                                                     struct eap_tnc_data *data)
00182 {
00183         switch (data->recommendation) {
00184         case ALLOW:
00185                 eap_tnc_set_state(data, DONE);
00186                 break;
00187         case ISOLATE:
00188                 eap_tnc_set_state(data, FAIL);
00189                 /* TODO: support assignment to a different VLAN */
00190                 break;
00191         case NO_ACCESS:
00192                 eap_tnc_set_state(data, FAIL);
00193                 break;
00194         case NO_RECOMMENDATION:
00195                 eap_tnc_set_state(data, DONE);
00196                 break;
00197         default:
00198                 wpa_printf(MSG_DEBUG, "EAP-TNC: Unknown recommendation");
00199                 return NULL;
00200         }
00201 
00202         return eap_tnc_build(sm, data);
00203 }
00204 
00205 
00206 static struct wpabuf * eap_tnc_build_frag_ack(u8 id, u8 code)
00207 {
00208         struct wpabuf *msg;
00209 
00210         msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, 1, code, id);
00211         if (msg == NULL) {
00212                 wpa_printf(MSG_ERROR, "EAP-TNC: Failed to allocate memory "
00213                            "for fragment ack");
00214                 return NULL;
00215         }
00216         wpabuf_put_u8(msg, EAP_TNC_VERSION); /* Flags */
00217 
00218         wpa_printf(MSG_DEBUG, "EAP-TNC: Send fragment ack");
00219 
00220         return msg;
00221 }
00222 
00223 
00224 static struct wpabuf * eap_tnc_build_msg(struct eap_tnc_data *data, u8 id)
00225 {
00226         struct wpabuf *req;
00227         u8 flags;
00228         size_t send_len, plen;
00229 
00230         wpa_printf(MSG_DEBUG, "EAP-TNC: Generating Request");
00231 
00232         flags = EAP_TNC_VERSION;
00233         send_len = wpabuf_len(data->out_buf) - data->out_used;
00234         if (1 + send_len > data->fragment_size) {
00235                 send_len = data->fragment_size - 1;
00236                 flags |= EAP_TNC_FLAGS_MORE_FRAGMENTS;
00237                 if (data->out_used == 0) {
00238                         flags |= EAP_TNC_FLAGS_LENGTH_INCLUDED;
00239                         send_len -= 4;
00240                 }
00241         }
00242 
00243         plen = 1 + send_len;
00244         if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
00245                 plen += 4;
00246         req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TNC, plen,
00247                             EAP_CODE_REQUEST, id);
00248         if (req == NULL)
00249                 return NULL;
00250 
00251         wpabuf_put_u8(req, flags); /* Flags */
00252         if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)
00253                 wpabuf_put_be32(req, wpabuf_len(data->out_buf));
00254 
00255         wpabuf_put_data(req, wpabuf_head_u8(data->out_buf) + data->out_used,
00256                         send_len);
00257         data->out_used += send_len;
00258 
00259         if (data->out_used == wpabuf_len(data->out_buf)) {
00260                 wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
00261                            "(message sent completely)",
00262                            (unsigned long) send_len);
00263                 wpabuf_free(data->out_buf);
00264                 data->out_buf = NULL;
00265                 data->out_used = 0;
00266                 if (data->was_fail)
00267                         eap_tnc_set_state(data, FAIL);
00268                 else if (data->was_done)
00269                         eap_tnc_set_state(data, DONE);
00270         } else {
00271                 wpa_printf(MSG_DEBUG, "EAP-TNC: Sending out %lu bytes "
00272                            "(%lu more to send)", (unsigned long) send_len,
00273                            (unsigned long) wpabuf_len(data->out_buf) -
00274                            data->out_used);
00275                 if (data->state == FAIL)
00276                         data->was_fail = 1;
00277                 else if (data->state == DONE)
00278                         data->was_done = 1;
00279                 eap_tnc_set_state(data, WAIT_FRAG_ACK);
00280         }
00281 
00282         return req;
00283 }
00284 
00285 
00286 static struct wpabuf * eap_tnc_buildReq(struct eap_sm *sm, void *priv, u8 id)
00287 {
00288         struct eap_tnc_data *data = priv;
00289 
00290         switch (data->state) {
00291         case START:
00292                 tncs_init_connection(data->tncs);
00293                 return eap_tnc_build_start(sm, data, id);
00294         case CONTINUE:
00295                 if (data->out_buf == NULL) {
00296                         data->out_buf = eap_tnc_build(sm, data);
00297                         if (data->out_buf == NULL) {
00298                                 wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
00299                                            "generate message");
00300                                 return NULL;
00301                         }
00302                         data->out_used = 0;
00303                 }
00304                 return eap_tnc_build_msg(data, id);
00305         case RECOMMENDATION:
00306                 if (data->out_buf == NULL) {
00307                         data->out_buf = eap_tnc_build_recommendation(sm, data);
00308                         if (data->out_buf == NULL) {
00309                                 wpa_printf(MSG_DEBUG, "EAP-TNC: Failed to "
00310                                            "generate recommendation message");
00311                                 return NULL;
00312                         }
00313                         data->out_used = 0;
00314                 }
00315                 return eap_tnc_build_msg(data, id);
00316         case WAIT_FRAG_ACK:
00317                 return eap_tnc_build_msg(data, id);
00318         case FRAG_ACK:
00319                 return eap_tnc_build_frag_ack(id, EAP_CODE_REQUEST);
00320         case DONE:
00321         case FAIL:
00322                 return NULL;
00323         }
00324 
00325         return NULL;
00326 }
00327 
00328 
00329 static Boolean eap_tnc_check(struct eap_sm *sm, void *priv,
00330                              struct wpabuf *respData)
00331 {
00332         struct eap_tnc_data *data = priv;
00333         const u8 *pos;
00334         size_t len;
00335 
00336         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData,
00337                                &len);
00338         if (pos == NULL) {
00339                 wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame");
00340                 return TRUE;
00341         }
00342 
00343         if (len == 0 && data->state != WAIT_FRAG_ACK) {
00344                 wpa_printf(MSG_INFO, "EAP-TNC: Invalid frame (empty)");
00345                 return TRUE;
00346         }
00347 
00348         if (len == 0)
00349                 return FALSE; /* Fragment ACK does not include flags */
00350 
00351         if ((*pos & EAP_TNC_VERSION_MASK) != EAP_TNC_VERSION) {
00352                 wpa_printf(MSG_DEBUG, "EAP-TNC: Unsupported version %d",
00353                            *pos & EAP_TNC_VERSION_MASK);
00354                 return TRUE;
00355         }
00356 
00357         if (*pos & EAP_TNC_FLAGS_START) {
00358                 wpa_printf(MSG_DEBUG, "EAP-TNC: Peer used Start flag");
00359                 return TRUE;
00360         }
00361 
00362         return FALSE;
00363 }
00364 
00365 
00366 static void tncs_process(struct eap_tnc_data *data, struct wpabuf *inbuf)
00367 {
00368         enum tncs_process_res res;
00369 
00370         res = tncs_process_if_tnccs(data->tncs, wpabuf_head(inbuf),
00371                                     wpabuf_len(inbuf));
00372         switch (res) {
00373         case TNCCS_RECOMMENDATION_ALLOW:
00374                 wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS allowed access");
00375                 eap_tnc_set_state(data, RECOMMENDATION);
00376                 data->recommendation = ALLOW;
00377                 break;
00378         case TNCCS_RECOMMENDATION_NO_RECOMMENDATION:
00379                 wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS has no recommendation");
00380                 eap_tnc_set_state(data, RECOMMENDATION);
00381                 data->recommendation = NO_RECOMMENDATION;
00382                 break;
00383         case TNCCS_RECOMMENDATION_ISOLATE:
00384                 wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS requested isolation");
00385                 eap_tnc_set_state(data, RECOMMENDATION);
00386                 data->recommendation = ISOLATE;
00387                 break;
00388         case TNCCS_RECOMMENDATION_NO_ACCESS:
00389                 wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS rejected access");
00390                 eap_tnc_set_state(data, RECOMMENDATION);
00391                 data->recommendation = NO_ACCESS;
00392                 break;
00393         case TNCCS_PROCESS_ERROR:
00394                 wpa_printf(MSG_DEBUG, "EAP-TNC: TNCS processing error");
00395                 eap_tnc_set_state(data, FAIL);
00396                 break;
00397         default:
00398                 break;
00399         }
00400 }
00401 
00402 
00403 static int eap_tnc_process_cont(struct eap_tnc_data *data,
00404                                 const u8 *buf, size_t len)
00405 {
00406         /* Process continuation of a pending message */
00407         if (len > wpabuf_tailroom(data->in_buf)) {
00408                 wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment overflow");
00409                 eap_tnc_set_state(data, FAIL);
00410                 return -1;
00411         }
00412 
00413         wpabuf_put_data(data->in_buf, buf, len);
00414         wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes, waiting for %lu "
00415                    "bytes more", (unsigned long) len,
00416                    (unsigned long) wpabuf_tailroom(data->in_buf));
00417 
00418         return 0;
00419 }
00420 
00421 
00422 static int eap_tnc_process_fragment(struct eap_tnc_data *data,
00423                                     u8 flags, u32 message_length,
00424                                     const u8 *buf, size_t len)
00425 {
00426         /* Process a fragment that is not the last one of the message */
00427         if (data->in_buf == NULL && !(flags & EAP_TNC_FLAGS_LENGTH_INCLUDED)) {
00428                 wpa_printf(MSG_DEBUG, "EAP-TNC: No Message Length field in a "
00429                            "fragmented packet");
00430                 return -1;
00431         }
00432 
00433         if (data->in_buf == NULL) {
00434                 /* First fragment of the message */
00435                 data->in_buf = wpabuf_alloc(message_length);
00436                 if (data->in_buf == NULL) {
00437                         wpa_printf(MSG_DEBUG, "EAP-TNC: No memory for "
00438                                    "message");
00439                         return -1;
00440                 }
00441                 wpabuf_put_data(data->in_buf, buf, len);
00442                 wpa_printf(MSG_DEBUG, "EAP-TNC: Received %lu bytes in first "
00443                            "fragment, waiting for %lu bytes more",
00444                            (unsigned long) len,
00445                            (unsigned long) wpabuf_tailroom(data->in_buf));
00446         }
00447 
00448         return 0;
00449 }
00450 
00451 
00452 static void eap_tnc_process(struct eap_sm *sm, void *priv,
00453                             struct wpabuf *respData)
00454 {
00455         struct eap_tnc_data *data = priv;
00456         const u8 *pos, *end;
00457         size_t len;
00458         u8 flags;
00459         u32 message_length = 0;
00460         struct wpabuf tmpbuf;
00461 
00462         pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TNC, respData, &len);
00463         if (pos == NULL)
00464                 return; /* Should not happen; message already verified */
00465 
00466         end = pos + len;
00467 
00468         if (len == 1 && (data->state == DONE || data->state == FAIL)) {
00469                 wpa_printf(MSG_DEBUG, "EAP-TNC: Peer acknowledged the last "
00470                            "message");
00471                 return;
00472         }
00473 
00474         if (len == 0) {
00475                 /* fragment ack */
00476                 flags = 0;
00477         } else
00478                 flags = *pos++;
00479 
00480         if (flags & EAP_TNC_FLAGS_LENGTH_INCLUDED) {
00481                 if (end - pos < 4) {
00482                         wpa_printf(MSG_DEBUG, "EAP-TNC: Message underflow");
00483                         eap_tnc_set_state(data, FAIL);
00484                         return;
00485                 }
00486                 message_length = WPA_GET_BE32(pos);
00487                 pos += 4;
00488 
00489                 if (message_length < (u32) (end - pos)) {
00490                         wpa_printf(MSG_DEBUG, "EAP-TNC: Invalid Message "
00491                                    "Length (%d; %ld remaining in this msg)",
00492                                    message_length, (long) (end - pos));
00493                         eap_tnc_set_state(data, FAIL);
00494                         return;
00495                 }
00496         }
00497         wpa_printf(MSG_DEBUG, "EAP-TNC: Received packet: Flags 0x%x "
00498                    "Message Length %u", flags, message_length);
00499 
00500         if (data->state == WAIT_FRAG_ACK) {
00501                 if (len > 1) {
00502                         wpa_printf(MSG_DEBUG, "EAP-TNC: Unexpected payload "
00503                                    "in WAIT_FRAG_ACK state");
00504                         eap_tnc_set_state(data, FAIL);
00505                         return;
00506                 }
00507                 wpa_printf(MSG_DEBUG, "EAP-TNC: Fragment acknowledged");
00508                 eap_tnc_set_state(data, CONTINUE);
00509                 return;
00510         }
00511 
00512         if (data->in_buf && eap_tnc_process_cont(data, pos, end - pos) < 0) {
00513                 eap_tnc_set_state(data, FAIL);
00514                 return;
00515         }
00516                 
00517         if (flags & EAP_TNC_FLAGS_MORE_FRAGMENTS) {
00518                 if (eap_tnc_process_fragment(data, flags, message_length,
00519                                              pos, end - pos) < 0)
00520                         eap_tnc_set_state(data, FAIL);
00521                 else
00522                         eap_tnc_set_state(data, FRAG_ACK);
00523                 return;
00524         } else if (data->state == FRAG_ACK) {
00525                 wpa_printf(MSG_DEBUG, "EAP-TNC: All fragments received");
00526                 eap_tnc_set_state(data, CONTINUE);
00527         }
00528 
00529         if (data->in_buf == NULL) {
00530                 /* Wrap unfragmented messages as wpabuf without extra copy */
00531                 wpabuf_set(&tmpbuf, pos, end - pos);
00532                 data->in_buf = &tmpbuf;
00533         }
00534 
00535         wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-TNC: Received payload",
00536                           wpabuf_head(data->in_buf), wpabuf_len(data->in_buf));
00537         tncs_process(data, data->in_buf);
00538 
00539         if (data->in_buf != &tmpbuf)
00540                 wpabuf_free(data->in_buf);
00541         data->in_buf = NULL;
00542 }
00543 
00544 
00545 static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
00546 {
00547         struct eap_tnc_data *data = priv;
00548         return data->state == DONE || data->state == FAIL;
00549 }
00550 
00551 
00552 static Boolean eap_tnc_isSuccess(struct eap_sm *sm, void *priv)
00553 {
00554         struct eap_tnc_data *data = priv;
00555         return data->state == DONE;
00556 }
00557 
00558 
00559 int eap_server_tnc_register(void)
00560 {
00561         struct eap_method *eap;
00562         int ret;
00563 
00564         eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
00565                                       EAP_VENDOR_IETF, EAP_TYPE_TNC, "TNC");
00566         if (eap == NULL)
00567                 return -1;
00568 
00569         eap->init = eap_tnc_init;
00570         eap->reset = eap_tnc_reset;
00571         eap->buildReq = eap_tnc_buildReq;
00572         eap->check = eap_tnc_check;
00573         eap->process = eap_tnc_process;
00574         eap->isDone = eap_tnc_isDone;
00575         eap->isSuccess = eap_tnc_isSuccess;
00576 
00577         ret = eap_server_method_register(eap);
00578         if (ret)
00579                 eap_server_method_free(eap);
00580         return ret;
00581 }


wpa_supplicant_node
Author(s): Package maintained by Blaise Gassend
autogenerated on Thu Apr 24 2014 15:33:20