📄 peap.c
字号:
/* * peap.c contains the interfaces that are called from eap * * Version: $Id$ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2003 Alan DeKok <aland@freeradius.org> * Copyright 2006 The FreeRADIUS server project */#include <freeradius-devel/ident.h>RCSID("$Id$")#include "eap_peap.h"/* * Send protected EAP-Failure * * Result-TLV = Failure */static int eappeap_failure(EAP_HANDLER *handler, tls_session_t *tls_session){ uint8_t tlv_packet[11]; REQUEST *request = handler->request; RDEBUG2("FAILURE"); tlv_packet[0] = PW_EAP_REQUEST; tlv_packet[1] = handler->eap_ds->response->id +1; tlv_packet[2] = 0; tlv_packet[3] = 11; /* length of this packet */ tlv_packet[4] = PW_EAP_TLV; tlv_packet[5] = 0x80; tlv_packet[6] = EAP_TLV_ACK_RESULT; tlv_packet[7] = 0; tlv_packet[8] = 2; /* length of the data portion */ tlv_packet[9] = 0; tlv_packet[10] = EAP_TLV_FAILURE; (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 11); /* * FIXME: Check the return code. */ tls_handshake_send(tls_session); return 1;}/* * Send protected EAP-Success * * Result-TLV = Success */static int eappeap_success(EAP_HANDLER *handler, tls_session_t *tls_session){ uint8_t tlv_packet[11]; REQUEST *request = handler->request; RDEBUG2("SUCCESS"); tlv_packet[0] = PW_EAP_REQUEST; tlv_packet[1] = handler->eap_ds->response->id +1; tlv_packet[2] = 0; tlv_packet[3] = 11; /* length of this packet */ tlv_packet[4] = PW_EAP_TLV; tlv_packet[5] = 0x80; /* mandatory AVP */ tlv_packet[6] = EAP_TLV_ACK_RESULT; tlv_packet[7] = 0; tlv_packet[8] = 2; /* length of the data portion */ tlv_packet[9] = 0; tlv_packet[10] = EAP_TLV_SUCCESS; (tls_session->record_plus)(&tls_session->clean_in, tlv_packet, 11); /* * FIXME: Check the return code. */ tls_handshake_send(tls_session); return 1;}/* * Verify the tunneled EAP message. */static int eapmessage_verify(REQUEST *request, const uint8_t *data, unsigned int data_len){ const eap_packet_t *eap_packet = (const eap_packet_t *) data; uint8_t eap_type; char buffer[256]; if (!data || (data_len <= 1)) { return 0; } eap_type = *data; switch (eap_type) { case PW_EAP_IDENTITY: RDEBUG2("Identity - %*s", data_len - 1, data + 1); return 1; break; /* * If the first byte of the packet is * EAP-Response, and the EAP data is a TLV, * then it looks OK... */ case PW_EAP_RESPONSE: if (eap_packet->data[0] == PW_EAP_TLV) { RDEBUG2("Received EAP-TLV response."); return 1; } RDEBUG2("Got something weird."); break; /* * We normally do Microsoft MS-CHAPv2 (26), versus * Cisco MS-CHAPv2 (29). */ case PW_EAP_MSCHAPV2: default: RDEBUG2("EAP type %s", eaptype_type2name(eap_type, buffer, sizeof(buffer))); return 1; break; } return 0;}/* * Convert a pseudo-EAP packet to a list of VALUE_PAIR's. */static VALUE_PAIR *eap2vp(REQUEST *request, EAP_DS *eap_ds, const uint8_t *data, size_t data_len){ size_t total; VALUE_PAIR *vp = NULL, *head, **tail; if (data_len > 65535) return NULL; /* paranoia */ vp = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS); if (!vp) { RDEBUG2("Failure in creating VP"); return NULL; } total = data_len; if (total > 249) total = 249; /* * Hand-build an EAP packet from the crap in PEAP version 0. */ vp->vp_octets[0] = PW_EAP_RESPONSE; vp->vp_octets[1] = eap_ds->response->id; vp->vp_octets[2] = (data_len + EAP_HEADER_LEN) >> 8; vp->vp_octets[3] = (data_len + EAP_HEADER_LEN) & 0xff; memcpy(vp->vp_octets + EAP_HEADER_LEN, data, total); vp->length = EAP_HEADER_LEN + total; head = vp; tail = &(vp->next); while (total < data_len) { int vp_len; vp = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS); if (!vp) { RDEBUG2("Failure in creating VP"); pairfree(&head); return NULL; } vp_len = (data_len - total); if (vp_len > 253) vp_len = 253; memcpy(vp->vp_octets, data + total, vp_len); vp->length = vp_len; total += vp_len; *tail = vp; tail = &(vp->next); } return head;}/* * Convert a list of VALUE_PAIR's to an EAP packet, through the * simple expedient of dumping the EAP message */static int vp2eap(tls_session_t *tls_session, VALUE_PAIR *vp){ /* * Skip the id, code, and length. Just write the EAP * type & data to the client. */#ifndef NDEBUG if ((debug_flag > 2) && fr_log_fp) { size_t i, total; VALUE_PAIR *this; total = 0; for (this = vp; this != NULL; this = this->next) { int start = 0; if (this == vp) start = EAP_HEADER_LEN; for (i = start; i < vp->length; i++) { if ((total & 0x0f) == 0) fprintf(fr_log_fp, " PEAP tunnel data out %04x: ", total); fprintf(fr_log_fp, "%02x ", vp->vp_octets[i]); if ((total & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n"); total++; } } if ((total & 0x0f) != 0) fprintf(fr_log_fp, "\n"); }#endif /* * Send the EAP data, WITHOUT the header. */ (tls_session->record_plus)(&tls_session->clean_in, vp->vp_octets + EAP_HEADER_LEN, vp->length - EAP_HEADER_LEN); /* * Send the rest of the EAP data. */ for (vp = vp->next; vp != NULL; vp = vp->next) { (tls_session->record_plus)(&tls_session->clean_in, vp->vp_octets, vp->length); } tls_handshake_send(tls_session); return 1;}/* * See if there's a TLV in the response. */static int eappeap_check_tlv(REQUEST *request, const uint8_t *data){ const eap_packet_t *eap_packet = (const eap_packet_t *) data; /* * Look for success or failure. */ if ((eap_packet->code == PW_EAP_RESPONSE) && (eap_packet->data[0] == PW_EAP_TLV)) { if (data[10] == EAP_TLV_SUCCESS) { return 1; } if (data[10] == EAP_TLV_FAILURE) { RDEBUG2("Client rejected our response. The password is probably incorrect."); return 0; } } return 0;}/* * Use a reply packet to determine what to do. */static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session, REQUEST *request, RADIUS_PACKET *reply){ int rcode = RLM_MODULE_REJECT; VALUE_PAIR *vp; peap_tunnel_t *t = tls_session->opaque; if ((debug_flag > 0) && fr_log_fp) { RDEBUG("Got tunneled reply RADIUS code %d", reply->code); debug_pair_list(reply->vps); } switch (reply->code) { case PW_AUTHENTICATION_ACK: RDEBUG2("Tunneled authentication was successful."); t->status = PEAP_STATUS_SENT_TLV_SUCCESS; eappeap_success(handler, tls_session); rcode = RLM_MODULE_HANDLED; /* * If we've been told to use the attributes from * the reply, then do so. * * WARNING: This may leak information about the * tunneled user! */ if (t->use_tunneled_reply) { RDEBUG2("Saving tunneled attributes for later"); /* * Clean up the tunneled reply. */ pairdelete(&reply->vps, PW_PROXY_STATE); pairdelete(&reply->vps, PW_EAP_MESSAGE); pairdelete(&reply->vps, PW_MESSAGE_AUTHENTICATOR); t->accept_vps = reply->vps; reply->vps = NULL; } break; case PW_AUTHENTICATION_REJECT: RDEBUG2("Tunneled authentication was rejected."); t->status = PEAP_STATUS_SENT_TLV_FAILURE; eappeap_failure(handler, tls_session); rcode = RLM_MODULE_HANDLED; break; case PW_ACCESS_CHALLENGE: RDEBUG2("Got tunneled Access-Challenge"); /* * Keep the State attribute, if necessary. * * Get rid of the old State, too. */ pairfree(&t->state); pairmove2(&t->state, &(reply->vps), PW_STATE); /* * PEAP takes only EAP-Message attributes inside * of the tunnel. Any Reply-Message in the * Access-Challenge is ignored. */ vp = NULL; pairmove2(&vp, &(reply->vps), PW_EAP_MESSAGE); /* * Handle EAP-MSCHAP-V2, where Access-Accept's * from the home server may contain MS-CHAP-Success, * which the module turns into challenges, so that * the client may respond to the challenge with * an "ack" packet. */ if (t->home_access_accept && t->use_tunneled_reply) { RDEBUG2("Saving tunneled attributes for later"); /* * Clean up the tunneled reply. */ pairdelete(&reply->vps, PW_PROXY_STATE); pairdelete(&reply->vps, PW_MESSAGE_AUTHENTICATOR); t->accept_vps = reply->vps; reply->vps = NULL; } /* * Handle the ACK, by tunneling any necessary reply * VP's back to the client. */ if (vp) { vp2eap(tls_session, vp); pairfree(&vp); } rcode = RLM_MODULE_HANDLED; break; default: RDEBUG2("Unknown RADIUS packet type %d: rejecting tunneled user", reply->code); rcode = RLM_MODULE_REJECT; break; } return rcode;}/* * Do post-proxy processing, */static int eappeap_postproxy(EAP_HANDLER *handler, void *data){ int rcode; tls_session_t *tls_session = (tls_session_t *) data; REQUEST *fake, *request = handler->request; RDEBUG2("Passing reply from proxy back into the tunnel."); /* * If there was a fake request associated with the proxied * request, do more processing of it. */ fake = (REQUEST *) request_data_get(handler->request, handler->request->proxy, REQUEST_DATA_EAP_MSCHAP_TUNNEL_CALLBACK); /* * Do the callback, if it exists, and if it was a success. */ if (fake && (handler->request->proxy_reply->code == PW_AUTHENTICATION_ACK)) { peap_tunnel_t *t = tls_session->opaque; t->home_access_accept = TRUE; /* * Terrible hacks. */ rad_assert(fake->packet == NULL); fake->packet = request->proxy; fake->packet->src_ipaddr = request->packet->src_ipaddr; request->proxy = NULL; rad_assert(fake->reply == NULL); fake->reply = request->proxy_reply; request->proxy_reply = NULL; if ((debug_flag > 0) && fr_log_fp) { fprintf(fr_log_fp, "server %s {\n", fake->server); } /* * Perform a post-auth stage, which will get the EAP * handler, too... */ fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; RDEBUG2("Passing reply back for EAP-MS-CHAP-V2"); rcode = module_post_proxy(0, fake); /* * FIXME: If rcode returns fail, do something * intelligent... */ rcode = rad_postauth(fake); if ((debug_flag > 0) && fr_log_fp) { fprintf(fr_log_fp, "} # server %s\n", fake->server); RDEBUG("Final reply from tunneled session code %d", fake->reply->code); debug_pair_list(fake->reply->vps); } /* * Terrible hacks. */ request->proxy = fake->packet; fake->packet = NULL; request->proxy_reply = fake->reply; fake->reply = NULL; /* * And we're done with this request. */ switch (rcode) { case RLM_MODULE_FAIL: request_free(&fake); eaptls_fail(handler, 0); return 0; break; default: /* Don't Do Anything */ RDEBUG2("Got reply %d", request->proxy_reply->code); break; } } request_free(&fake); /* robust if fake == NULL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -