2 * eapcommon.c rfc2284 & rfc2869 implementation
4 * code common to clients and to servers.
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 * Copyright 2000-2003,2006 The FreeRADIUS server project
23 * Copyright 2001 hereUare Communications, Inc. <raghud@hereuare.com>
24 * Copyright 2003 Alan DeKok <aland@freeradius.org>
25 * Copyright 2003 Michael Richardson <mcr@sandelman.ottawa.on.ca>
31 * 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
32 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
33 * | Code | Identifier | Length |
34 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
39 * EAP Request and Response Packet Format
40 * --- ------- --- -------- ------ ------
42 * 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
43 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
44 * | Code | Identifier | Length |
45 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
46 * | Type | Type-Data ...
47 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-
50 * EAP Success and Failure Packet Format
51 * --- ------- --- ------- ------ ------
53 * 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
54 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
55 * | Code | Identifier | Length |
56 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
60 #include <freeradius-devel/ident.h>
63 #include <freeradius-devel/autoconf.h>
64 #include <freeradius-devel/missing.h>
65 #include <freeradius-devel/libradius.h>
66 #include "eap_types.h"
68 static const char *eap_types[] = {
87 "sim", /* 18 GSM-SIM authentication */
98 "cisco_mschapv2", /* 29 */
119 }; /* MUST have PW_EAP_MAX_TYPES */
122 * Return an EAP-Type for a particular name.
124 int eaptype_name2type(const char *name)
128 for (i = 0; i <= PW_EAP_MAX_TYPES; i++) {
129 if (strcmp(name, eap_types[i]) == 0) {
138 * Returns a text string containing the name of the EAP type.
140 const char *eaptype_type2name(unsigned int type, char *buffer, size_t buflen)
144 if (type > PW_EAP_MAX_TYPES) {
146 * Prefer the dictionary name over a number,
149 dval = dict_valbyattr(PW_EAP_TYPE, 0, type);
151 snprintf(buffer, buflen, "%s", dval->name);
154 snprintf(buffer, buflen, "%d", type);
156 } else if ((*eap_types[type] >= '0') && (*eap_types[type] <= '9')) {
158 * Prefer the dictionary name, if it exists.
160 dval = dict_valbyattr(PW_EAP_TYPE, 0, type);
162 snprintf(buffer, buflen, "%s", dval->name);
164 } /* else it wasn't in the dictionary */
165 } /* else the name in the array was non-numeric */
168 * Return the name, whatever it is.
170 return eap_types[type];
174 * EAP packet format to be sent over the wire
176 * i.e. code+id+length+data where data = null/type+typedata
179 * INPUT to function is reply->code
181 * reply->type - setup with data
183 * OUTPUT reply->packet is setup with wire format, and will
184 * be malloc()'ed to the right size.
187 int eap_wireformat(EAP_PACKET *reply)
190 uint16_t total_length = 0;
192 if (reply == NULL) return EAP_INVALID;
195 * If reply->packet is set, then the wire format
196 * has already been calculated, just succeed.
198 if(reply->packet != NULL) return EAP_VALID;
200 total_length = EAP_HEADER_LEN;
201 if (reply->code < 3) {
202 total_length += 1/*EAPtype*/;
203 if (reply->type.data && reply->type.length > 0) {
204 total_length += reply->type.length;
208 reply->packet = (unsigned char *)malloc(total_length);
209 hdr = (eap_packet_t *)reply->packet;
211 radlog(L_ERR, "rlm_eap: out of memory");
215 hdr->code = (reply->code & 0xFF);
216 hdr->id = (reply->id & 0xFF);
217 total_length = htons(total_length);
218 memcpy(hdr->length, &total_length, sizeof(total_length));
221 * Request and Response packets are special.
223 if ((reply->code == PW_EAP_REQUEST) ||
224 (reply->code == PW_EAP_RESPONSE)) {
225 hdr->data[0] = (reply->type.type & 0xFF);
228 * Here since we cannot know the typedata format and length
230 * Type_data is expected to be wired by each EAP-Type
232 * Zero length/No typedata is supported as long as
235 if (reply->type.data && reply->type.length > 0) {
236 memcpy(&hdr->data[1], reply->type.data, reply->type.length);
237 free(reply->type.data);
238 reply->type.data = reply->packet + EAP_HEADER_LEN + 1/*EAPtype*/;
247 * compose EAP reply packet in EAP-Message attr of RADIUS. If
248 * EAP exceeds 253, frame it in multiple EAP-Message attrs.
250 int eap_basic_compose(RADIUS_PACKET *packet, EAP_PACKET *reply)
253 eap_packet_t *eap_packet;
256 if (eap_wireformat(reply) == EAP_INVALID) {
257 return RLM_MODULE_INVALID;
259 eap_packet = (eap_packet_t *)reply->packet;
261 pairdelete(&(packet->vps), PW_EAP_MESSAGE, 0);
263 vp = eap_packet2vp(eap_packet);
264 if (!vp) return RLM_MODULE_INVALID;
265 pairadd(&(packet->vps), vp);
268 * EAP-Message is always associated with
269 * Message-Authenticator but not vice-versa.
271 * Don't add a Message-Authenticator if it's already
274 vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR, 0);
276 vp = paircreate(PW_MESSAGE_AUTHENTICATOR, 0, PW_TYPE_OCTETS);
277 memset(vp->vp_strvalue, 0, AUTH_VECTOR_LEN);
278 vp->length = AUTH_VECTOR_LEN;
279 pairadd(&(packet->vps), vp);
282 /* Set request reply code, but only if it's not already set. */
283 rcode = RLM_MODULE_OK;
284 if (!packet->code) switch(reply->code) {
285 case PW_EAP_RESPONSE:
287 packet->code = PW_AUTHENTICATION_ACK;
288 rcode = RLM_MODULE_HANDLED;
291 packet->code = PW_AUTHENTICATION_REJECT;
292 rcode = RLM_MODULE_REJECT;
295 packet->code = PW_ACCESS_CHALLENGE;
296 rcode = RLM_MODULE_HANDLED;
299 /* Should never enter here */
300 radlog(L_ERR, "rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code);
301 packet->code = PW_AUTHENTICATION_REJECT;
309 VALUE_PAIR *eap_packet2vp(const eap_packet_t *packet)
313 VALUE_PAIR *head = NULL;
314 VALUE_PAIR **tail = &head;
317 total = packet->length[0] * 256 + packet->length[1];
319 ptr = (const uint8_t *) packet;
323 if (size > 253) size = 253;
325 vp = paircreate(PW_EAP_MESSAGE, 0, PW_TYPE_OCTETS);
330 memcpy(vp->vp_octets, ptr, size);
345 * Handles multiple EAP-Message attrs
346 * ie concatenates all to get the complete EAP packet.
348 * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message,
349 * refer fragmentation in rfc2869.
351 eap_packet_t *eap_vp2packet(VALUE_PAIR *vps)
353 VALUE_PAIR *first, *vp;
354 eap_packet_t *eap_packet;
360 * Get only EAP-Message attribute list
362 first = pairfind(vps, PW_EAP_MESSAGE, 0);
364 DEBUG("rlm_eap: EAP-Message not found");
369 * Sanity check the length before doing anything.
371 if (first->length < 4) {
372 DEBUG("rlm_eap: EAP packet is too short.");
377 * Get the Actual length from the EAP packet
378 * First EAP-Message contains the EAP packet header
380 memcpy(&len, first->vp_strvalue + 2, sizeof(len));
384 * Take out even more weird things.
387 DEBUG("rlm_eap: EAP packet has invalid length.");
392 * Sanity check the length, BEFORE malloc'ing memory.
395 for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0)) {
396 total_len += vp->length;
398 if (total_len > len) {
399 DEBUG("rlm_eap: Malformed EAP packet. Length in packet header does not match actual length");
405 * If the length is SMALLER, die, too.
407 if (total_len < len) {
408 DEBUG("rlm_eap: Malformed EAP packet. Length in packet header does not match actual length");
413 * Now that we know the lengths are OK, allocate memory.
415 eap_packet = (eap_packet_t *) malloc(len);
416 if (eap_packet == NULL) {
417 radlog(L_ERR, "rlm_eap: out of memory");
422 * Copy the data from EAP-Message's over to our EAP packet.
424 ptr = (unsigned char *)eap_packet;
426 /* RADIUS ensures order of attrs, so just concatenate all */
427 for (vp = first; vp; vp = pairfind(vp->next, PW_EAP_MESSAGE, 0)) {
428 memcpy(ptr, vp->vp_strvalue, vp->length);
435 VALUE_PAIR *eap_chbind_packet2vp(const eap_chbind_packet_t *packet, size_t len)
439 VALUE_PAIR *head = NULL;
440 VALUE_PAIR **tail = &head;
443 ptr = (const uint8_t *) packet;
447 if (size > 247) size = 247;
449 vp = paircreate(PW_UKERNA_CHBIND, VENDORPEC_UKERNA,
455 memcpy(vp->vp_octets, ptr, size);
470 * Handles multiple EAP-channel-binding Message attrs
471 * ie concatenates all to get the complete EAP-channel-binding packet.
473 size_t eap_chbind_vp2packet(VALUE_PAIR *vps, eap_chbind_packet_t **result)
475 VALUE_PAIR *first, *vp;
476 eap_chbind_packet_t *eap_chbind_packet;
480 first = pairfind(vps, PW_UKERNA_CHBIND, VENDORPEC_UKERNA);
483 * Compute total length
487 vp = pairfind(vp->next, PW_UKERNA_CHBIND, VENDORPEC_UKERNA)) {
492 * Now that we know the length, allocate memory.
494 eap_chbind_packet = (eap_chbind_packet_t *) malloc(len);
495 if (eap_chbind_packet == NULL) {
496 radlog(L_ERR, "rlm_eap: out of memory");
501 * Copy the data from EAP-Message's over to our EAP packet.
503 ptr = (unsigned char *)eap_chbind_packet;
505 /* RADIUS ensures order of attrs, so just concatenate all */
507 vp = pairfind(vp->next, PW_UKERNA_CHBIND, VENDORPEC_UKERNA)) {
508 memcpy(ptr, vp->vp_octets, vp->length);
512 *result = eap_chbind_packet;