*
* 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
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*
- * Copyright 2000-2003 The FreeRADIUS server project
+ * Copyright 2000-2003,2006 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>
*
*/
-#include "libradius.h"
-#include "eap_types.h"
+#include <freeradius-devel/ident.h>
+RCSID("$Id$")
-static const char rcsid[] = "$Id$";
+#include <freeradius-devel/libradius.h>
+#include "eap_types.h"
static const char *eap_types[] = {
"",
"mschapv2", /* 26 */
"27",
"28",
- "cisco_mschapv2" /* 29 */
-};
-#define MAX_EAP_TYPE_NAME 29
+ "cisco_mschapv2", /* 29 */
+ "30",
+ "31",
+ "32",
+ "33",
+ "34",
+ "35",
+ "36",
+ "37",
+ "tnc", /* 38 */
+ "39",
+ "40",
+ "41",
+ "42",
+ "fast",
+ "44",
+ "45",
+ "pax",
+ "psk",
+ "sake",
+ "ikev2",
+ "50",
+ "51",
+ "pwd"
+}; /* MUST have PW_EAP_MAX_TYPES */
/*
* Return an EAP-Type for a particular name.
{
DICT_VALUE *dval;
- if (type > MAX_EAP_TYPE_NAME) {
+ if (type > PW_EAP_MAX_TYPES) {
/*
* Prefer the dictionary name over a number,
* if it exists.
*/
- dval = dict_valbyattr(PW_EAP_TYPE, type);
+ dval = dict_valbyattr(PW_EAP_TYPE, 0, type);
if (dval) {
snprintf(buffer, buflen, "%s", dval->name);
}
/*
* Prefer the dictionary name, if it exists.
*/
- dval = dict_valbyattr(PW_EAP_TYPE, type);
+ dval = dict_valbyattr(PW_EAP_TYPE, 0, type);
if (dval) {
snprintf(buffer, buflen, "%s", dval->name);
return buffer;
* be malloc()'ed to the right size.
*
*/
-static int eap_wireformat(EAP_PACKET *reply)
+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 is set, then the wire format
+ * has already been calculated, just succeed.
*/
- if(reply->packet != NULL)
- {
- return EAP_VALID;
- }
+ if(reply->packet != NULL) return EAP_VALID;
total_length = EAP_HEADER_LEN;
if (reply->code < 3) {
hdr->code = (reply->code & 0xFF);
hdr->id = (reply->id & 0xFF);
total_length = htons(total_length);
- memcpy(hdr->length, &total_length, sizeof(uint16_t));
+ memcpy(hdr->length, &total_length, sizeof(total_length));
/*
* Request and Response packets are special.
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) {
}
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;
- }
+ pairdelete(&(packet->vps), PW_EAP_MESSAGE, 0, TAG_ANY);
- /*
- * 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);
+ vp = eap_packet2vp(eap_packet);
+ if (!vp) return RLM_MODULE_INVALID;
+ pairadd(&(packet->vps), vp);
/*
* EAP-Message is always associated with
* Don't add a Message-Authenticator if it's already
* there.
*/
- vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR);
+ vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
if (!vp) {
- vp = paircreate(PW_MESSAGE_AUTHENTICATOR, PW_TYPE_OCTETS);
- memset(vp->strvalue, 0, AUTH_VECTOR_LEN);
+ vp = paircreate(PW_MESSAGE_AUTHENTICATOR, 0);
+ memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN);
vp->length = AUTH_VECTOR_LEN;
pairadd(&(packet->vps), vp);
}
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 *eap_packet2vp(const eap_packet_t *packet)
{
- 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;
- }
+ int total, size;
+ const uint8_t *ptr;
+ VALUE_PAIR *head = NULL;
+ VALUE_PAIR **tail = &head;
+ VALUE_PAIR *vp;
- vp = pairfind(req->vps, ATTRIBUTE_EAP_CODE);
- if(vp == NULL) {
- eapcode = PW_EAP_REQUEST;
- } else {
- eapcode = vp->lvalue;
- }
+ total = packet->length[0] * 256 + packet->length[1];
+ ptr = (const uint8_t *) packet;
- for(vp = req->vps; vp != NULL; vp = vpnext) {
- /* save it in case it changes! */
- vpnext = vp->next;
+ do {
+ size = total;
+ if (size > 253) size = 253;
- if(vp->attribute >= ATTRIBUTE_EAP_BASE &&
- vp->attribute < ATTRIBUTE_EAP_BASE+256) {
- break;
+ vp = paircreate(PW_EAP_MESSAGE, 0);
+ if (!vp) {
+ pairfree(&head);
+ return NULL;
}
- }
+ memcpy(vp->vp_octets, ptr, size);
+ vp->length = size;
- if(vp == NULL) {
- return;
- }
+ *tail = vp;
+ tail = &(vp->next);
- 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.
- */
+ ptr += size;
+ total -= size;
+ } while (total > 0);
- /* 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);
- }
+ return head;
}
+
/*
* 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)
+eap_packet_t *eap_vp2packet(VALUE_PAIR *vps)
{
VALUE_PAIR *first, *vp;
eap_packet_t *eap_packet;
/*
* Get only EAP-Message attribute list
*/
- first = pairfind(vps, PW_EAP_MESSAGE);
+ first = pairfind(vps, PW_EAP_MESSAGE, 0, TAG_ANY);
if (first == NULL) {
- radlog(L_ERR, "rlm_eap: EAP-Message not found");
+ DEBUG("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.");
+ DEBUG("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));
+ memcpy(&len, first->vp_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.");
+ DEBUG("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)) {
+ for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0, TAG_ANY)) {
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");
+ DEBUG("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");
+ DEBUG("rlm_eap: Malformed EAP packet. Length in packet header does not match actual length");
return NULL;
}
}
/*
- * Copy the data from EAP-Message's over to out EAP packet.
+ * Copy the data from EAP-Message's over to our 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);
+ for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0, TAG_ANY)) {
+ memcpy(ptr, vp->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 *eap_chbind_packet2vp(const eap_chbind_packet_t *packet, size_t len)
{
- VALUE_PAIR *eap1;
- eap_packet_t *e;
- int len;
- int type;
+ size_t size;
+ const uint8_t *ptr;
+ VALUE_PAIR *head = NULL;
+ VALUE_PAIR **tail = &head;
+ VALUE_PAIR *vp;
- /* find eap message */
- e = eap_attribute(rep->vps);
+ ptr = (const uint8_t *) packet;
- /* nothing to do! */
- if(e == NULL) return;
+ do {
+ size = len;
+ if (size > 247) size = 247;
- /* 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);
+ vp = paircreate(PW_VENDOR_SPECIFIC, VENDORPEC_UKERNA,
+ PW_TYPE_OCTETS);
+ if (!vp) {
+ pairfree(&head);
+ return NULL;
+ }
+ vp->vp_octets[0] = PW_UKERNA_CHBIND;
+ vp->vp_octets[1] = size;
+ memcpy(&vp->vp_octets[2], ptr, size);
+ vp->length = size + 2;
- eap1 = paircreate(ATTRIBUTE_EAP_CODE, PW_TYPE_INTEGER);
- eap1->lvalue = e->code;
- pairadd(&(rep->vps), eap1);
+ *tail = vp;
+ tail = &(vp->next);
- switch(e->code)
- {
- default:
- case PW_EAP_SUCCESS:
- case PW_EAP_FAILURE:
- /* no data */
- break;
+ ptr += size;
+ len -= size;
+ } while (len > 0);
- case PW_EAP_REQUEST:
- case PW_EAP_RESPONSE:
- /* there is a type field, which we use to create
- * a new attribute */
+ return head;
+}
- /* 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;
- }
+/*
+ * Find the next EAP-CHANNEL-BINDING message in the
+ * pair list
+ */
+static VALUE_PAIR *eap_chbind_find_pair(VALUE_PAIR *vps)
+{
+ VALUE_PAIR *result = pairfind(vps, PW_VENDOR_SPECIFIC,
+ VENDORPEC_UKERNA);
+ while (result && (result->vp_octets[0] != PW_UKERNA_CHBIND))
+ result = result->next;
+ return result;
+}
- type = e->data[0];
+/*
+ * Handles multiple EAP-channel-binding Message attrs
+ * ie concatenates all to get the complete EAP-channel-binding packet.
+ */
+size_t eap_chbind_vp2packet(VALUE_PAIR *vps, eap_chbind_packet_t **result)
+{
+ VALUE_PAIR *first, *vp;
+ eap_chbind_packet_t *eap_chbind_packet;
+ unsigned char *ptr;
+ size_t len;
- type += ATTRIBUTE_EAP_BASE;
- len -= 5;
+ first = eap_chbind_find_pair(vps);
- if(len > MAX_STRING_LEN) {
- len = MAX_STRING_LEN;
+ /*
+ * Sanity check the length, BEFORE malloc'ing memory.
+ */
+ len = 0;
+ for (vp = first; vp; vp = eap_chbind_find_pair(vp)) {
+ if ((vp->length < 2) ||
+ (vp->length != vp->vp_octets[1]+2)) {
+ DEBUG("rlm_eap: Malformed EAP channel binding value pair. Length in pair header does not match actual length");
+ return 0;
}
+ len += vp->vp_octets[1];
+ }
- eap1 = paircreate(type, PW_TYPE_OCTETS);
- memcpy(eap1->strvalue, &e->data[1], len);
- eap1->length = len;
- pairadd(&(rep->vps), eap1);
- break;
+ /*
+ * Now that we know the lengths are OK, allocate memory.
+ */
+ eap_chbind_packet = (eap_chbind_packet_t *) malloc(len);
+ if (eap_chbind_packet == NULL) {
+ radlog(L_ERR, "rlm_eap: out of memory");
+ return 0;
}
- return;
-}
+ /*
+ * Copy the data from EAP-Message's over to our EAP packet.
+ */
+ ptr = (unsigned char *)eap_chbind_packet;
+ /* RADIUS ensures order of attrs, so just concatenate all */
+ for (vp = first; vp; vp = eap_chbind_find_pair(vp->next)) {
+ memcpy(ptr, vp->vp_octets+2, vp->length-2);
+ ptr += vp->length-2;
+ }
+
+ *result = eap_chbind_packet;
+ return len;
+}