📄 eapcommon.c
字号:
/* * eapcommon.c rfc2284 & rfc2869 implementation * * code common to clients and to servers. * * Version: $Id: eapcommon.c,v 1.5 2004/03/19 02:22:19 mcr 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 2000-2003 The FreeRADIUS server project * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com> * Copyright 2003 Alan DeKok <aland@freeradius.org> * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca> *//* * EAP PACKET FORMAT * --- ------ ------ * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Code | Identifier | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Data ... * +-+-+-+-+ * * * EAP Request and Response Packet Format * --- ------- --- -------- ------ ------ * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Code | Identifier | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Type | Type-Data ... * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+- * * * EAP Success and Failure Packet Format * --- ------- --- ------- ------ ------ * 0 1 2 3 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Code | Identifier | Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * */#include "libradius.h"#include "eap_types.h"static const char rcsid[] = "$Id: eapcommon.c,v 1.5 2004/03/19 02:22:19 mcr Exp $";static const char *eap_types[] = { "", "identity", "notification", "nak", /* NAK */ "md5", "otp", "gtc", "7", "8", "9", "10", "11", "12", "tls", /* 13 */ "14", "15", "16", "leap", /* 17 */ "sim", /* 18 GSM-SIM authentication */ "19", "20", "ttls", /* 21 */ "22", "23", "24", "peap", /* 25 */ "mschapv2", /* 26 */ "27", "28", "cisco_mschapv2" /* 29 */};#define MAX_EAP_TYPE_NAME 29/* * Return an EAP-Type for a particular name. */int eaptype_name2type(const char *name){ int i; for (i = 0; i <= PW_EAP_MAX_TYPES; i++) { if (strcmp(name, eap_types[i]) == 0) { return i; } } return -1;}/* * Returns a text string containing the name of the EAP type. */const char *eaptype_type2name(unsigned int type, char *buffer, size_t buflen){ DICT_VALUE *dval; if (type > MAX_EAP_TYPE_NAME) { /* * Prefer the dictionary name over a number, * if it exists. */ dval = dict_valbyattr(PW_EAP_TYPE, type); if (dval) { snprintf(buffer, buflen, "%s", dval->name); } snprintf(buffer, buflen, "%d", type); return buffer; } else if ((*eap_types[type] >= '0') && (*eap_types[type] <= '9')) { /* * Prefer the dictionary name, if it exists. */ dval = dict_valbyattr(PW_EAP_TYPE, type); if (dval) { snprintf(buffer, buflen, "%s", dval->name); return buffer; } /* else it wasn't in the dictionary */ } /* else the name in the array was non-numeric */ /* * Return the name, whatever it is. */ return eap_types[type];}/* * EAP packet format to be sent over the wire * * i.e. code+id+length+data where data = null/type+typedata * based on code. * * INPUT to function is reply->code * reply->id * reply->type - setup with data * * OUTPUT reply->packet is setup with wire format, and will * be malloc()'ed to the right size. * */static int eap_wireformat(EAP_PACKET *reply){ eap_packet_t *hdr; uint16_t total_length = 0; if (reply == NULL) return EAP_INVALID; /* * if reply->packet is set, then the wire format * has already been calculated, just succeed! */ if(reply->packet != NULL) { return EAP_VALID; } total_length = EAP_HEADER_LEN; if (reply->code < 3) { total_length += 1/*EAPtype*/; if (reply->type.data && reply->type.length > 0) { total_length += reply->type.length; } } reply->packet = (unsigned char *)malloc(total_length); hdr = (eap_packet_t *)reply->packet; if (!hdr) { radlog(L_ERR, "rlm_eap: out of memory"); return EAP_INVALID; } hdr->code = (reply->code & 0xFF); hdr->id = (reply->id & 0xFF); total_length = htons(total_length); memcpy(hdr->length, &total_length, sizeof(uint16_t)); /* * Request and Response packets are special. */ if ((reply->code == PW_EAP_REQUEST) || (reply->code == PW_EAP_RESPONSE)) { hdr->data[0] = (reply->type.type & 0xFF); /* * Here since we cannot know the typedata format and length * * Type_data is expected to be wired by each EAP-Type * * Zero length/No typedata is supported as long as * type is defined */ if (reply->type.data && reply->type.length > 0) { memcpy(&hdr->data[1], reply->type.data, reply->type.length); free(reply->type.data); reply->type.data = reply->packet + EAP_HEADER_LEN + 1/*EAPtype*/; } } return EAP_VALID;}/* * compose EAP reply packet in EAP-Message attr of RADIUS. If * EAP exceeds 253, frame it in multiple EAP-Message attrs. */int eap_basic_compose(RADIUS_PACKET *packet, EAP_PACKET *reply){ uint16_t eap_len, len; VALUE_PAIR *eap_msg; VALUE_PAIR *vp; eap_packet_t *eap_packet; unsigned char *ptr; int rcode; if (eap_wireformat(reply) == EAP_INVALID) { return RLM_MODULE_INVALID; } eap_packet = (eap_packet_t *)reply->packet; memcpy(&eap_len, &(eap_packet->length), sizeof(uint16_t)); len = eap_len = ntohs(eap_len); ptr = (unsigned char *)eap_packet; pairdelete(&(packet->vps), PW_EAP_MESSAGE); do { if (eap_len > 253) { len = 253; eap_len -= 253; } else { len = eap_len; eap_len = 0; } /* * create a value pair & append it to the packet list * This memory gets freed up when packet is freed up */ eap_msg = paircreate(PW_EAP_MESSAGE, PW_TYPE_OCTETS); memcpy(eap_msg->strvalue, ptr, len); eap_msg->length = len; pairadd(&(packet->vps), eap_msg); ptr += len; eap_msg = NULL; } while (eap_len); /* * EAP-Message is always associated with * Message-Authenticator but not vice-versa. * * Don't add a Message-Authenticator if it's already * there. */ vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR); if (!vp) { vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS); memset(vp->strvalue, 0, AUTH_VECTOR_LEN); vp->length = AUTH_VECTOR_LEN; pairadd(&(packet->vps), vp); } /* Set request reply code, but only if it's not already set. */ rcode = RLM_MODULE_OK; if (!packet->code) switch(reply->code) { case PW_EAP_RESPONSE: case PW_EAP_SUCCESS: packet->code = PW_AUTHENTICATION_ACK; rcode = RLM_MODULE_HANDLED; break; case PW_EAP_FAILURE: packet->code = PW_AUTHENTICATION_REJECT; rcode = RLM_MODULE_REJECT; break; case PW_EAP_REQUEST: packet->code = PW_ACCESS_CHALLENGE; rcode = RLM_MODULE_HANDLED; break; default: /* Should never enter here */ radlog(L_ERR, "rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code); packet->code = PW_AUTHENTICATION_REJECT; break; } return rcode;}/* * given a radius request with some attributes in the EAP range, build * them all into a single EAP-Message body. * * Note that this function will build multiple EAP-Message bodies * if there are multiple eligible EAP-types. This is incorrect, as the * recipient will in fact concatenate them. * * XXX - we could break the loop once we process one type. Maybe this * just deserves an assert? * */void map_eap_types(RADIUS_PACKET *req){ VALUE_PAIR *vp, *vpnext; int id, eapcode; EAP_PACKET ep; int eap_type; vp = pairfind(req->vps, ATTRIBUTE_EAP_ID); if(vp == NULL) { id = ((int)getpid() & 0xff); } else { id = vp->lvalue; } vp = pairfind(req->vps, ATTRIBUTE_EAP_CODE); if(vp == NULL) { eapcode = PW_EAP_REQUEST; } else { eapcode = vp->lvalue; } for(vp = req->vps; vp != NULL; vp = vpnext) { /* save it in case it changes! */ vpnext = vp->next; if(vp->attribute >= ATTRIBUTE_EAP_BASE && vp->attribute < ATTRIBUTE_EAP_BASE+256) { break; } } if(vp == NULL) { return; } eap_type = vp->attribute - ATTRIBUTE_EAP_BASE; switch(eap_type) { case PW_EAP_IDENTITY: case PW_EAP_NOTIFICATION: case PW_EAP_NAK: case PW_EAP_MD5: case PW_EAP_OTP: case PW_EAP_GTC: case PW_EAP_TLS: case PW_EAP_LEAP: case PW_EAP_TTLS: case PW_EAP_PEAP: default: /* * no known special handling, it is just encoded as an * EAP-message with the given type. */ /* nuke any existing EAP-Messages */ pairdelete(&req->vps, PW_EAP_MESSAGE); memset(&ep, 0, sizeof(ep)); ep.code = eapcode; ep.id = id; ep.type.type = eap_type; ep.type.length = vp->length; ep.type.data = vp->strvalue; eap_basic_compose(req, &ep); }}/* * Handles multiple EAP-Message attrs * ie concatenates all to get the complete EAP packet. * * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message, * refer fragmentation in rfc2869. */eap_packet_t *eap_attribute(VALUE_PAIR *vps){ VALUE_PAIR *first, *vp; eap_packet_t *eap_packet; unsigned char *ptr; uint16_t len; int total_len; /* * Get only EAP-Message attribute list */ first = pairfind(vps, PW_EAP_MESSAGE); if (first == NULL) { radlog(L_ERR, "rlm_eap: EAP-Message not found"); return NULL; } /* * Sanity check the length before doing anything. */ if (first->length < 4) { radlog(L_ERR, "rlm_eap: EAP packet is too short."); return NULL; } /* * Get the Actual length from the EAP packet * First EAP-Message contains the EAP packet header */ memcpy(&len, first->strvalue + 2, sizeof(len)); len = ntohs(len); /* * Take out even more weird things. */ if (len < 4) { radlog(L_ERR, "rlm_eap: EAP packet has invalid length."); return NULL; } /* * Sanity check the length, BEFORE malloc'ing memory. */ total_len = 0; for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE)) { total_len += vp->length; if (total_len > len) { radlog(L_ERR, "rlm_eap: Malformed EAP packet. Length in packet header does not match actual length"); return NULL; } } /* * If the length is SMALLER, die, too. */ if (total_len < len) { radlog(L_ERR, "rlm_eap: Malformed EAP packet. Length in packet header does not match actual length"); return NULL; } /* * Now that we know the lengths are OK, allocate memory. */ eap_packet = (eap_packet_t *) malloc(len); if (eap_packet == NULL) { radlog(L_ERR, "rlm_eap: out of memory"); return NULL; } /* * Copy the data from EAP-Message's over to out EAP packet. */ ptr = (unsigned char *)eap_packet; /* RADIUS ensures order of attrs, so just concatenate all */ for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE)) { memcpy(ptr, vp->strvalue, vp->length); ptr += vp->length; } return eap_packet;}/* * given a radius request with an EAP-Message body, decode it specific * attributes. */void unmap_eap_types(RADIUS_PACKET *rep){ VALUE_PAIR *eap1; eap_packet_t *e; int len; int type; /* find eap message */ e = eap_attribute(rep->vps); /* nothing to do! */ if(e == NULL) return; /* create EAP-ID and EAP-CODE attributes to start */ eap1 = paircreate(ATTRIBUTE_EAP_ID, PW_TYPE_INTEGER); eap1->lvalue = e->id; pairadd(&(rep->vps), eap1); eap1 = paircreate(ATTRIBUTE_EAP_CODE, PW_TYPE_INTEGER); eap1->lvalue = e->code; pairadd(&(rep->vps), eap1); switch(e->code) { default: case PW_EAP_SUCCESS: case PW_EAP_FAILURE: /* no data */ break; case PW_EAP_REQUEST: case PW_EAP_RESPONSE: /* there is a type field, which we use to create * a new attribute */ /* the length was decode already into the attribute * length, and was checked already. Network byte * order, just pull it out using math. */ len = e->length[0]*256 + e->length[1]; /* verify the length is big enough to hold type */ if(len < 5) { return; } type = e->data[0]; type += ATTRIBUTE_EAP_BASE; len -= 5; if(len > MAX_STRING_LEN) { len = MAX_STRING_LEN; } eap1 = paircreate(type, PW_TYPE_OCTETS); memcpy(eap1->strvalue, &e->data[1], len); eap1->length = len; pairadd(&(rep->vps), eap1); break; } return;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -