📄 peap.c
字号:
/* * peap.c contains the interfaces that are called from eap * * Version: $Id: peap.c,v 1.11 2004/03/12 18:23:14 aland Exp $ * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Copyright 2003 Alan DeKok <aland@freeradius.org> */#include "eap_tls.h"#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]; DEBUG2(" rlm_eap_peap: 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; record_plus(&tls_session->clean_in, tlv_packet, 11); /* * FIXME: Check the return code. */ tls_handshake_send(tls_session); record_init(&tls_session->clean_in); 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]; DEBUG2(" rlm_eap_peap: 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; record_plus(&tls_session->clean_in, tlv_packet, 11); /* * FIXME: Check the return code. */ tls_handshake_send(tls_session); record_init(&tls_session->clean_in); return 1;}/* * Verify the tunneled EAP message. */static int eapmessage_verify(const uint8_t *data, unsigned int data_len){ const eap_packet_t *eap_packet = (const eap_packet_t *) data; uint8_t eap_type; char identity[256]; if (!data || (data_len <= 1)) { return 0; } eap_type = *data; switch (eap_type) { case PW_EAP_IDENTITY: memcpy(identity, data + 1, data_len - 1); identity[data_len - 1] = '\0'; DEBUG2(" rlm_eap_peap: Identity - %s", identity); 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) { DEBUG2(" rlm_eap_peap: Received EAP-TLV response."); return 1; } DEBUG2(" rlm_eap_peap: Got something weird."); break; /* * We normally do Microsoft MS-CHAPv2 (26), versus * Cisco MS-CHAPv2 (29). */ case PW_EAP_MSCHAPV2: default: DEBUG2(" rlm_eap_peap: EAP type %s", eaptype_type2name(eap_type, identity, sizeof(identity))); return 1; break; } return 0;}/* * Convert a pseudo-EAP packet to a list of VALUE_PAIR's. */static VALUE_PAIR *eap2vp(EAP_DS *eap_ds, const uint8_t *data, unsigned int data_len){ VALUE_PAIR *vp = NULL; /* * Sanity check this... */ if (data_len + EAP_HEADER_LEN > MAX_STRING_LEN) { radlog(L_ERR, "rlm_eap_peap: EAP Response packet is too large. Code must be fixed to handle this."); return NULL; } vp = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS); if (!vp) { DEBUG2(" rlm_eap_peap: Failure in creating VP"); return NULL; } /* * Hand-build an EAP packet from the crap in PEAP version 0. */ vp->strvalue[0] = PW_EAP_RESPONSE; vp->strvalue[1] = eap_ds->response->id; vp->strvalue[2] = 0; vp->strvalue[3] = EAP_HEADER_LEN + data_len; memcpy(vp->strvalue + EAP_HEADER_LEN, data, data_len); vp->length = EAP_HEADER_LEN + data_len; return vp;}/* * 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){ if (vp->next != NULL) { radlog(L_ERR, "rlm_eap_peap: EAP Request packet is too large. Code must be fixed to handle this."); return 0; } /* * Skip the id, code, and length. Just write the EAP * type & data to the client. */#ifndef NDEBUG if (debug_flag > 2) { int i; int total = vp->length - 4; if (debug_flag > 0) for (i = 0; i < total; i++) { if ((i & 0x0f) == 0) printf(" PEAP tunnel data out %04x: ", i); printf("%02x ", vp->strvalue[i + 4]); if ((i & 0x0f) == 0x0f) printf("\n"); } if ((total & 0x0f) != 0) printf("\n"); }#endif /* * Send the EAP data, WITHOUT the header. */#if 1 record_plus(&tls_session->clean_in, vp->strvalue + EAP_HEADER_LEN, vp->length - EAP_HEADER_LEN);#else record_plus(&tls_session->clean_in, vp->strvalue, vp->length);#endif tls_handshake_send(tls_session); record_init(&tls_session->clean_in); return 1;}/* * See if there's a TLV in the response. */static int eappeap_check_tlv(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) { DEBUG2(" rlm_eap_peap: 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;#ifndef NDEBUG if (debug_flag > 0) { printf(" PEAP: Processing from tunneled session code %p %d\n", reply, reply->code); for (vp = reply->vps; vp != NULL; vp = vp->next) { putchar('\t');vp_print(stdout, vp);putchar('\n'); } }#endif switch (reply->code) { case PW_AUTHENTICATION_ACK: DEBUG2(" PEAP: 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) { /* * Clean up the tunneled reply. */ pairdelete(&reply->vps, PW_PROXY_STATE); pairdelete(&reply->vps, PW_EAP_MESSAGE); pairadd(&request->reply->vps, reply->vps); reply->vps = NULL; } break; case PW_AUTHENTICATION_REJECT: DEBUG2(" PEAP: 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: DEBUG2(" PEAP: 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 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: DEBUG2(" PEAP: 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; DEBUG2(" PEAP: 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)) { VALUE_PAIR *vp; REQUEST *request = handler->request; /* * Terrible hacks. */ rad_assert(fake->packet == NULL); fake->packet = request->proxy; request->proxy = NULL; rad_assert(fake->reply == NULL); fake->reply = request->proxy_reply; request->proxy_reply = NULL; /* * Perform a post-auth stage, which will get the EAP * handler, too... */ fake->options &= ~RAD_REQUEST_OPTION_PROXY_EAP; DEBUG2(" PEAP: Passing reply back for EAP-MS-CHAP-V2 %p %d", fake, fake->reply->code); rcode = module_post_proxy(fake); /* * FIXME: If rcode returns fail, do something * intelligent... */ DEBUG2(" POST-PROXY %d", rcode); rcode = rad_postauth(fake); DEBUG2(" POST-AUTH %d", rcode);#ifndef NDEBUG if (debug_flag > 0) { printf(" PEAP: Final reply from tunneled session code %d\n", fake->reply->code); for (vp = fake->reply->vps; vp != NULL; vp = vp->next) { putchar('\t');vp_print(stdout, vp);putchar('\n'); } }#endif /* * 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->eap_ds, 0); return 0; break; default: /* Don't Do Anything */ DEBUG2(" PEAP: Got reply %d", request->proxy_reply->code); break; } } request_free(&fake); /* robust if fake == NULL */ /* * If there was no EAP-Message in the reply packet, then * we know that we're supposed to re-run the "authenticate" * stage, in order to get the right kind of handling... */ /* * Process the reply from the home server. */ rcode = process_reply(handler, tls_session, handler->request, handler->request->proxy_reply); /* * The proxy code uses the reply from the home server as * the basis for the reply to the NAS. We don't want that, * so we toss it, after we've had our way with it. */ pairfree(&handler->request->proxy_reply->vps); switch (rcode) { case RLM_MODULE_REJECT: DEBUG2(" PEAP: Reply was rejected"); eaptls_fail(handler->eap_ds, 0); return 0; case RLM_MODULE_HANDLED: DEBUG2(" PEAP: Reply was handled"); eaptls_request(handler->eap_ds, tls_session); return 1; case RLM_MODULE_OK:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -