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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
62 #include <freeradius-devel/libradius.h>
63 #include <freeradius-devel/rad_assert.h>
64 #include "eap_types.h"
66 const FR_NAME_NUMBER eap_rcode_table[] = {
67 { "notfound", EAP_NOTFOUND },
71 { "noop", EAP_INVALID },
72 { "invalid", EAP_VALID },
73 { "valid", EAP_MAX_RCODES },
78 /** Return an EAP-Type for a particular name
80 * Converts a name into an IANA EAP type.
82 * @param name to convert.
83 * @return The IANA EAP type or PW_EAP_INVALID if the name doesn't match any
86 eap_type_t eap_name2type(char const *name)
90 dv = dict_valbyname(PW_EAP_TYPE, 0, name);
91 if (!dv) return PW_EAP_INVALID;
93 if (dv->value >= PW_EAP_MAX_TYPES) return PW_EAP_INVALID;
98 /** Return an EAP-name for a particular type
102 char const *eap_type2name(eap_type_t method)
106 dv = dict_valbyattr(PW_EAP_TYPE, 0, method);
115 * EAP packet format to be sent over the wire
117 * i.e. code+id+length+data where data = null/type+typedata
120 * INPUT to function is reply->code
122 * reply->type - setup with data
124 * OUTPUT reply->packet is setup with wire format, and will
125 * be allocated to the right size.
128 int eap_wireformat(eap_packet_t *reply)
130 eap_packet_raw_t *header;
131 uint16_t total_length = 0;
133 if (!reply) return EAP_INVALID;
136 * If reply->packet is set, then the wire format
137 * has already been calculated, just succeed.
139 if(reply->packet != NULL) return EAP_VALID;
141 total_length = EAP_HEADER_LEN;
142 if (reply->code < 3) {
143 total_length += 1/* EAP Method */;
144 if (reply->type.data && reply->type.length > 0) {
145 total_length += reply->type.length;
149 reply->packet = talloc_array(reply, uint8_t, total_length);
150 header = (eap_packet_raw_t *)reply->packet;
155 header->code = (reply->code & 0xFF);
156 header->id = (reply->id & 0xFF);
158 total_length = htons(total_length);
159 memcpy(header->length, &total_length, sizeof(total_length));
162 * Request and Response packets are special.
164 if ((reply->code == PW_EAP_REQUEST) ||
165 (reply->code == PW_EAP_RESPONSE)) {
166 header->data[0] = (reply->type.num & 0xFF);
169 * Here since we cannot know the typedata format and length
171 * Type_data is expected to be wired by each EAP-Type
173 * Zero length/No typedata is supported as long as
176 if (reply->type.data && reply->type.length > 0) {
177 memcpy(&header->data[1], reply->type.data, reply->type.length);
178 talloc_free(reply->type.data);
179 reply->type.data = reply->packet + EAP_HEADER_LEN + 1/*EAPtype*/;
188 * compose EAP reply packet in EAP-Message attr of RADIUS. If
189 * EAP exceeds 253, frame it in multiple EAP-Message attrs.
191 int eap_basic_compose(RADIUS_PACKET *packet, eap_packet_t *reply)
194 eap_packet_raw_t *eap_packet;
197 if (eap_wireformat(reply) == EAP_INVALID) {
198 return RLM_MODULE_INVALID;
200 eap_packet = (eap_packet_raw_t *)reply->packet;
202 pairdelete(&(packet->vps), PW_EAP_MESSAGE, 0, TAG_ANY);
204 vp = eap_packet2vp(packet, eap_packet);
205 if (!vp) return RLM_MODULE_INVALID;
206 pairadd(&(packet->vps), vp);
209 * EAP-Message is always associated with
210 * Message-Authenticator but not vice-versa.
212 * Don't add a Message-Authenticator if it's already
215 vp = pairfind(packet->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY);
217 vp = paircreate(packet, PW_MESSAGE_AUTHENTICATOR, 0);
218 vp->length = AUTH_VECTOR_LEN;
219 vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->length);
221 pairadd(&(packet->vps), vp);
224 /* Set request reply code, but only if it's not already set. */
225 rcode = RLM_MODULE_OK;
226 if (!packet->code) switch(reply->code) {
227 case PW_EAP_RESPONSE:
229 packet->code = PW_CODE_ACCESS_ACCEPT;
230 rcode = RLM_MODULE_HANDLED;
233 packet->code = PW_CODE_ACCESS_REJECT;
234 rcode = RLM_MODULE_REJECT;
237 packet->code = PW_CODE_ACCESS_CHALLENGE;
238 rcode = RLM_MODULE_HANDLED;
241 /* Should never enter here */
242 ERROR("rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code);
243 packet->code = PW_CODE_ACCESS_REJECT;
251 VALUE_PAIR *eap_packet2vp(RADIUS_PACKET *packet, eap_packet_raw_t const *eap)
255 VALUE_PAIR *head = NULL;
259 total = eap->length[0] * 256 + eap->length[1];
262 DEBUG("Asked to encode empty EAP-Message!");
266 ptr = (uint8_t const *) eap;
268 fr_cursor_init(&out, &head);
271 if (size > 253) size = 253;
273 vp = paircreate(packet, PW_EAP_MESSAGE, 0);
278 pairmemcpy(vp, ptr, size);
280 fr_cursor_insert(&out, vp);
291 * Handles multiple EAP-Message attrs
292 * ie concatenates all to get the complete EAP packet.
294 * NOTE: Sometimes Framed-MTU might contain the length of EAP-Message,
295 * refer fragmentation in rfc2869.
297 eap_packet_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps)
299 VALUE_PAIR *first, *i;
300 eap_packet_raw_t *eap_packet;
307 * Get only EAP-Message attribute list
309 first = pairfind(vps, PW_EAP_MESSAGE, 0, TAG_ANY);
311 DEBUG("rlm_eap: EAP-Message not found");
316 * Sanity check the length before doing anything.
318 if (first->length < 4) {
319 DEBUG("rlm_eap: EAP packet is too short");
324 * Get the Actual length from the EAP packet
325 * First EAP-Message contains the EAP packet header
327 memcpy(&len, first->vp_strvalue + 2, sizeof(len));
331 * Take out even more weird things.
334 DEBUG("rlm_eap: EAP packet has invalid length");
339 * Sanity check the length, BEFORE allocating memory.
342 fr_cursor_init(&cursor, &first);
343 while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) {
344 total_len += i->length;
346 if (total_len > len) {
347 DEBUG("rlm_eap: Malformed EAP packet. Length in packet header does not match actual length");
353 * If the length is SMALLER, die, too.
355 if (total_len < len) {
356 DEBUG("rlm_eap: Malformed EAP packet. Length in packet header does not match actual length");
361 * Now that we know the lengths are OK, allocate memory.
363 eap_packet = (eap_packet_raw_t *) talloc_zero_array(ctx, uint8_t, len);
369 * Copy the data from EAP-Message's over to our EAP packet.
371 ptr = (unsigned char *)eap_packet;
373 /* RADIUS ensures order of attrs, so just concatenate all */
374 fr_cursor_first(&cursor);
375 while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) {
376 memcpy(ptr, i->vp_strvalue, i->length);
384 * Add raw hex data to the reply.
386 void eap_add_reply(REQUEST *request,
387 char const *name, uint8_t const *value, int len)
391 vp = pairmake_reply(name, NULL, T_OP_EQ);
393 REDEBUG("Did not create attribute %s: %s\n",
394 name, fr_strerror());
398 pairmemcpy(vp, value, len);