eap_tnc.c

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