From af754e596a8dbb05ed8580c342e7fe02e08b28e0 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 13 Apr 2024 16:11:00 +0200 Subject: Adding upstream version 3.2.3+dfsg. Signed-off-by: Daniel Baumann --- src/modules/rlm_eap/libeap/eapcommon.c | 401 +++++++++++++++++++++++++++++++++ 1 file changed, 401 insertions(+) create mode 100644 src/modules/rlm_eap/libeap/eapcommon.c (limited to 'src/modules/rlm_eap/libeap/eapcommon.c') diff --git a/src/modules/rlm_eap/libeap/eapcommon.c b/src/modules/rlm_eap/libeap/eapcommon.c new file mode 100644 index 0000000..96db30b --- /dev/null +++ b/src/modules/rlm_eap/libeap/eapcommon.c @@ -0,0 +1,401 @@ +/* + * eapcommon.c rfc2284 & rfc2869 implementation + * + * code common to clients and to servers. + * + * Version: $Id$ + * + * 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + * Copyright 2000-2003,2006 The FreeRADIUS server project + * Copyright 2001 hereUare Communications, Inc. + * Copyright 2003 Alan DeKok + * Copyright 2003 Michael Richardson + */ +/* + * 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 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + */ + +RCSID("$Id$") + +#include +#include +#include "eap_types.h" + +const FR_NAME_NUMBER eap_rcode_table[] = { + { "notfound", EAP_NOTFOUND }, + { "found", EAP_OK }, + { "ok", EAP_FAIL }, + { "fail", EAP_NOOP }, + { "noop", EAP_INVALID }, + { "invalid", EAP_VALID }, + { "valid", EAP_MAX_RCODES }, + + { NULL , -1 } +}; + +/** Return an EAP-Type for a particular name + * + * Converts a name into an IANA EAP type. + * + * @param name to convert. + * @return The IANA EAP type or PW_EAP_INVALID if the name doesn't match any + * known types. + */ +eap_type_t eap_name2type(char const *name) +{ + DICT_VALUE *dv; + + dv = dict_valbyname(PW_EAP_TYPE, 0, name); + if (!dv) return PW_EAP_INVALID; + + if (dv->value >= PW_EAP_MAX_TYPES) return PW_EAP_INVALID; + + return dv->value; +} + +/** Return an EAP-name for a particular type + * + * Resolve + */ +char const *eap_type2name(eap_type_t method) +{ + DICT_VALUE *dv; + + dv = dict_valbyattr(PW_EAP_TYPE, 0, method); + if (dv) { + return dv->name; + } + + return "unknown"; +} + +/* + * 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 allocated to the right size. + * + */ +int eap_wireformat(eap_packet_t *reply) +{ + eap_packet_raw_t *header; + uint16_t total_length = 0; + + if (!reply) 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/* EAP Method */; + if (reply->type.data && reply->type.length > 0) { + total_length += reply->type.length; + } + } + + reply->packet = talloc_array(reply, uint8_t, total_length); + header = (eap_packet_raw_t *)reply->packet; + if (!header) { + return EAP_INVALID; + } + + header->code = (reply->code & 0xFF); + header->id = (reply->id & 0xFF); + + total_length = htons(total_length); + memcpy(header->length, &total_length, sizeof(total_length)); + + /* + * Request and Response packets are special. + */ + if ((reply->code == PW_EAP_REQUEST) || + (reply->code == PW_EAP_RESPONSE)) { + header->data[0] = (reply->type.num & 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(&header->data[1], reply->type.data, reply->type.length); + talloc_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_t *reply) +{ + VALUE_PAIR *vp; + eap_packet_raw_t *eap_packet; + int rcode; + + if (eap_wireformat(reply) == EAP_INVALID) { + return RLM_MODULE_INVALID; + } + eap_packet = (eap_packet_raw_t *)reply->packet; + + fr_pair_delete_by_num(&(packet->vps), PW_EAP_MESSAGE, 0, TAG_ANY); + + vp = eap_packet2vp(packet, eap_packet); + if (!vp) return RLM_MODULE_INVALID; + fr_pair_add(&(packet->vps), vp); + + /* + * EAP-Message is always associated with + * Message-Authenticator but not vice-versa. + * + * Don't add a Message-Authenticator if it's already + * there. + */ + vp = fr_pair_find_by_num(packet->vps, PW_MESSAGE_AUTHENTICATOR, 0, TAG_ANY); + if (!vp) { + vp = fr_pair_afrom_num(packet, PW_MESSAGE_AUTHENTICATOR, 0); + vp->vp_length = AUTH_VECTOR_LEN; + vp->vp_octets = talloc_zero_array(vp, uint8_t, vp->vp_length); + + fr_pair_add(&(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_CODE_ACCESS_ACCEPT; + rcode = RLM_MODULE_HANDLED; + break; + case PW_EAP_FAILURE: + packet->code = PW_CODE_ACCESS_REJECT; + rcode = RLM_MODULE_REJECT; + break; + case PW_EAP_REQUEST: + packet->code = PW_CODE_ACCESS_CHALLENGE; + rcode = RLM_MODULE_HANDLED; + break; + default: + /* Should never enter here */ + ERROR("rlm_eap: reply code %d is unknown, Rejecting the request.", reply->code); + packet->code = PW_CODE_ACCESS_REJECT; + break; + } + + return rcode; +} + + +VALUE_PAIR *eap_packet2vp(RADIUS_PACKET *packet, eap_packet_raw_t const *eap) +{ + int total, size; + uint8_t const *ptr; + VALUE_PAIR *head = NULL; + VALUE_PAIR *vp; + vp_cursor_t out; + + total = eap->length[0] * 256 + eap->length[1]; + + if (total == 0) { + DEBUG("Asked to encode empty EAP-Message!"); + return NULL; + } + + ptr = (uint8_t const *) eap; + + fr_cursor_init(&out, &head); + do { + size = total; + if (size > 253) size = 253; + + vp = fr_pair_afrom_num(packet, PW_EAP_MESSAGE, 0); + if (!vp) { + fr_pair_list_free(&head); + return NULL; + } + fr_pair_value_memcpy(vp, ptr, size); + + fr_cursor_insert(&out, vp); + + ptr += size; + total -= size; + } while (total > 0); + + 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_raw_t *eap_vp2packet(TALLOC_CTX *ctx, VALUE_PAIR *vps) +{ + VALUE_PAIR *first, *i; + eap_packet_raw_t *eap_packet; + unsigned char *ptr; + uint16_t len; + int total_len; + vp_cursor_t cursor; + + /* + * Get only EAP-Message attribute list + */ + first = fr_pair_find_by_num(vps, PW_EAP_MESSAGE, 0, TAG_ANY); + if (!first) { + fr_strerror_printf("EAP-Message not found"); + return NULL; + } + + /* + * Sanity check the length before doing anything. + */ + if (first->vp_length < 4) { + fr_strerror_printf("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->vp_strvalue + 2, sizeof(len)); + len = ntohs(len); + + /* + * Take out even more weird things. + */ + if (len < 4) { + fr_strerror_printf("EAP packet has invalid length (less than 4 bytes)"); + return NULL; + } + + /* + * Sanity check the length, BEFORE allocating memory. + */ + total_len = 0; + fr_cursor_init(&cursor, &first); + while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) { + total_len += i->vp_length; + + if (total_len > len) { + fr_strerror_printf("Malformed EAP packet. Length in packet header %i, " + "does not match actual length %i", len, total_len); + return NULL; + } + } + + /* + * If the length is SMALLER, die, too. + */ + if (total_len < len) { + fr_strerror_printf("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_raw_t *) talloc_zero_array(ctx, uint8_t, len); + if (!eap_packet) { + return NULL; + } + + /* + * 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 */ + fr_cursor_first(&cursor); + while ((i = fr_cursor_next_by_num(&cursor, PW_EAP_MESSAGE, 0, TAG_ANY))) { + memcpy(ptr, i->vp_strvalue, i->vp_length); + ptr += i->vp_length; + } + + return eap_packet; +} + +/* + * Add raw hex data to the reply. + */ +void eap_add_reply(REQUEST *request, + char const *name, uint8_t const *value, int len) +{ + VALUE_PAIR *vp; + + vp = pair_make_reply(name, NULL, T_OP_EQ); + if (!vp) { + REDEBUG("Did not create attribute %s: %s\n", + name, fr_strerror()); + return; + } + + fr_pair_value_memcpy(vp, value, len); +} -- cgit v1.2.3