26 RCSID(
"$Id: 3d9f4f3637711ad12cbd39bf532bc448a5dd6cd3 $")
28 #include <freeradius-devel/eap/chbind.h>
29 #include <freeradius-devel/tls/log.h>
30 #include <freeradius-devel/tls/strerror.h>
33 #define FR_DIAMETER_AVP_FLAG_VENDOR 0x80
34 #define FR_DIAMETER_AVP_FLAG_MANDATORY 0x40
57 unsigned int remaining = data_len;
59 while (remaining > 0) {
62 if (remaining < hdr_len) {
63 RDEBUG2(
"Diameter attribute is too small (%u) to contain a Diameter header", remaining);
67 memcpy(&attr,
data,
sizeof(attr));
69 memcpy(&length,
data + 4,
sizeof(length));
70 length = ntohl(length);
72 if ((
data[4] & 0x80) != 0) {
74 RDEBUG2(
"Diameter attribute is too small to contain a Diameter header with Vendor-Id");
89 if (length <= (hdr_len - 4)) {
90 RDEBUG2(
"Tunneled attribute %u is too short (%u < %u) to contain anything useful.", attr,
95 if (length > remaining) {
96 RDEBUG2(
"Tunneled attribute %u is longer than room remaining in the packet (%u > %u).", attr,
105 if (remaining == length)
break;
122 if (remaining < length) {
123 REDEBUG2(
"Diameter attribute overflows packet!");
152 SSL *ssl = decode_ctx;
156 TALLOC_CTX *tmp_ctx = NULL;
170 fr_strerror_printf(
"Malformed diameter attribute at offset %zu. Needed at least 8 bytes, got %zu bytes",
178 RDEBUG3(
"%04zu %02x%02x%02x%02x %02x%02x%02x%02x ...", p -
data,
179 p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
191 fr_strerror_printf(
"Malformed diameter attribute at offset %zu. Needed at least length of 8, got %u",
192 p -
data, (
unsigned int) value_len);
199 if ((p + ((value_len + 0x03) & ~0x03)) - 8 > end) {
200 fr_strerror_printf(
"Malformed diameter attribute at offset %zu. Value length %u overflows input",
201 p -
data, (
unsigned int) value_len);
235 our_parent = attr_radius;
282 p += (value_len + 0x03) & ~0x03;
285 if (
vp->
da->flags.is_unknown)
continue;
304 static const char label[] =
"ttls challenge";
306 if ((
vp->vp_length < 8) || (
vp->vp_length > 16)) {
315 if (SSL_export_keying_material(ssl, challenge,
vp->vp_length + 1,
316 label,
sizeof(label) - 1, NULL, 0, 0) != 1) {
317 fr_tls_strerror_printf(
"Failed generating phase2 challenge");
321 if (memcmp(challenge,
vp->vp_octets,
vp->vp_length) != 0) {
373 if ((total +
vp->vp_length + 12) >=
sizeof(
buffer)) {
374 RDEBUG2(
"output buffer is full!");
383 length =
vp->vp_length;
386 attr =
vp->
da->attr & 0xffff;
399 memcpy(p, &attr,
sizeof(attr));
408 length = ntohl(length);
409 memcpy(p, &length,
sizeof(length));
413 vendor = ntohl(vendor);
414 memcpy(p, &vendor,
sizeof(vendor));
418 length = ntohl(length);
419 memcpy(p, &length,
sizeof(length));
424 switch (
vp->vp_type) {
427 memcpy(p, &attr,
sizeof(attr));
432 attr = htonl(
vp->vp_uint32);
433 memcpy(p, &attr,
sizeof(attr));
438 attr64 = htonll(
vp->vp_uint64);
439 memcpy(p, &attr64,
sizeof(attr64));
444 memcpy(p, &
vp->vp_ipv4addr, 4);
451 memcpy(p,
vp->vp_strvalue,
vp->vp_length);
452 length =
vp->vp_length;
465 if ((total & 0x03) != 0) {
468 length = 4 - (total & 0x03);
469 for (i = 0; i < length; i++) {
481 (tls_session->record_from_buff)(&tls_session->clean_in,
buffer, total);
486 fr_tls_session_send(request, tls_session);
509 fr_assert(eap_session->request == request);
532 switch (reply->
code) {
535 RDEBUG2(
"Got tunneled Access-Accept");
547 RDEBUG2(
"Got MS-CHAP2-Success, tunneling it to the client in a challenge");
562 REDEBUG(
"Got tunneled Access-Reject");
573 RDEBUG2(
"Got tunneled Access-Challenge");
592 REDEBUG(
"Unknown RADIUS packet type %d: rejecting tunneled user", reply->
code);
603 RDEBUG2(
"Sending tunneled reply attributes");
633 data_len = tls_session->clean_out.used;
634 tls_session->clean_out.used = 0;
635 data = tls_session->clean_out.data;
645 RDEBUG2(
"Got ACK, and the user was already authenticated");
669 data, data_len, tls_session->ssl) < 0) {
670 RPEDEBUG(
"Decoding TTLS TLVs failed");
702 (
char const *)
vp->vp_octets + 5,
vp->vp_length - 5,
true);
711 RWDEBUG2(
"No EAP-Identity found to start EAP conversation");
729 RDEBUG2(
"received chbind request");
740 RDEBUG2(
"sending chbind response");
765 if (!request->reply->code) {
766 RDEBUG2(
"No tunneled reply was found for request %" PRIu64
", and the request was not "
767 "proxied: rejecting the user", request->number);
773 rcode =
process_reply(eap_session, tls_session, request, request->reply, &request->reply_pairs);
static int const char char buffer[256]
fr_radius_packet_code_t chbind_process(request_t *request, CHBIND_REQ *chbind)
chbind_packet_t * eap_chbind_vp2packet(TALLOC_CTX *ctx, fr_pair_list_t *vps)
fr_pair_t * eap_chbind_packet2vp(TALLOC_CTX *ctx, chbind_packet_t *chbind)
chbind_packet_t * response
chbind_packet_t * request
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
static int fr_dcursor_append(fr_dcursor_t *cursor, void *v)
Insert a single item at the end of the list.
static void fr_dcursor_free_list(fr_dcursor_t *cursor)
Free the current item and all items after it.
fr_radius_packet_code_t
RADIUS packet codes.
@ FR_RADIUS_CODE_ACCESS_CHALLENGE
RFC2865 - Access-Challenge.
@ FR_RADIUS_CODE_ACCESS_ACCEPT
RFC2865 - Access-Accept.
@ FR_RADIUS_CODE_ACCESS_REJECT
RFC2865 - Access-Reject.
fr_dict_attr_t const * fr_dict_vendor_da_by_num(fr_dict_attr_t const *vendor_root, uint32_t vendor_pen)
Return vendor attribute for the specified dictionary and pen.
fr_dict_t const * fr_dict_by_protocol_name(char const *name)
Lookup a protocol by its name.
fr_dict_attr_t const * fr_dict_root(fr_dict_t const *dict)
Return the root attribute of a dictionary.
fr_dict_attr_t * fr_dict_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor))
Build an unknown vendor, parented by a VSA attribute.
fr_dict_t const * fr_dict_internal(void)
fr_dict_attr_t const * fr_dict_attr_child_by_num(fr_dict_attr_t const *parent, unsigned int attr)
Check if a child attribute exists in a parent using an attribute number.
fr_dict_attr_t * fr_dict_unknown_attr_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int num))
Initialise a fr_dict_attr_t from a number.
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
Declarations for EAP-TTLS as defined by RFC 5281.
HIDDEN fr_dict_attr_t const * attr_reply_message
char const * virtual_server
HIDDEN fr_dict_attr_t const * attr_eap_channel_binding_message
HIDDEN fr_dict_attr_t const * attr_eap_message
rlm_rcode_t eap_virtual_server(UNUSED request_t *request, UNUSED eap_session_t *eap_session, UNUSED char const *virtual_server)
Run a subrequest through a virtual server, managing the eap_session_t of the child.
Tracks the progress of a single session of any EAP method.
void log_request_pair_list(fr_log_lvl_t lvl, request_t *request, fr_pair_t const *parent, fr_pair_list_t const *vps, char const *prefix)
Print a fr_pair_list_t.
#define RWDEBUG2(fmt,...)
#define RPEDEBUG(fmt,...)
#define REDEBUG2(fmt,...)
@ L_DBG_LVL_2
2nd highest priority debug messages (-xx | -X).
@ FR_TYPE_IPV4_ADDR
32 Bit IPv4 Address.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_DATE
Unix time stamp, always has value >2^31.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_UINT64
64 Bit unsigned integer.
@ FR_TYPE_OCTETS
Raw octets.
static uint64_t fr_nbo_to_uint64v(uint8_t const *data, size_t data_len)
Read an unsigned 64bit integer from wire format (big endian) with a variable length encoding.
static uint32_t fr_nbo_to_uint32(uint8_t const data[static sizeof(uint32_t)])
Read an unsigned 32bit integer from wire format (big endian)
fr_pair_t * fr_pair_find_by_da(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find the first pair with a matching da.
fr_pair_t * fr_pair_alloc_null(TALLOC_CTX *ctx)
Dynamically allocate a new attribute with no fr_dict_attr_t assigned.
fr_pair_t * fr_pair_afrom_da(TALLOC_CTX *ctx, fr_dict_attr_t const *da)
Dynamically allocate a new attribute and assign a fr_dict_attr_t.
int fr_pair_value_strdup(fr_pair_t *vp, char const *src, bool tainted)
Copy data into an "string" data type.
int fr_pair_append(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the end of the list.
void fr_pair_list_init(fr_pair_list_t *list)
Initialise a pair list header.
int fr_pair_value_bstrndup(fr_pair_t *vp, char const *src, size_t len, bool tainted)
Copy data into a "string" type value pair.
int fr_pair_reinit_from_da(fr_pair_list_t *list, fr_pair_t *vp, fr_dict_attr_t const *da)
Re-initialise an attribute with a different da.
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
int fr_pair_prepend(fr_pair_list_t *list, fr_pair_t *to_add)
Add a VP to the start of the list.
int fr_pair_raw_afrom_pair(fr_pair_t *vp, uint8_t const *data, size_t data_len)
Mark malformed attribute as raw.
static fr_dict_t const * dict_radius
static fr_dict_attr_t const * attr_ms_chap_challenge
static fr_dict_attr_t const * attr_chap_challenge
static fr_dict_attr_t const * attr_user_name
static fr_dict_attr_t const * attr_vendor_specific
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_INVALID
The module considers the request invalid.
@ RLM_MODULE_OK
The module is OK, continue.
@ RLM_MODULE_REJECT
Immediately reject the request.
@ RLM_MODULE_HANDLED
The module handled the request, so stop.
static fr_dict_attr_t const * attr_ms_chap2_success
if(!subtype_vp) goto fail
MEM(pair_append_request(&vp, attr_eap_aka_sim_identity) >=0)
Stores an attribute, a value and various bits of other data.
fr_dict_attr_t const *_CONST da
Dictionary attribute defines the attribute number, vendor and type of the pair.
static int64_t fr_unix_time_to_sec(fr_unix_time_t delta)
#define FR_DIAMETER_AVP_FLAG_MANDATORY
static rlm_rcode_t process_reply(NDEBUG_UNUSED eap_session_t *eap_session, fr_tls_session_t *tls_session, request_t *request, fr_packet_t *reply, fr_pair_list_t *reply_list)
fr_radius_packet_code_t eap_ttls_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
static int vp2diameter(request_t *request, fr_tls_session_t *tls_session, fr_pair_list_t *list)
static int diameter_verify(request_t *request, uint8_t const *data, unsigned int data_len)
static ssize_t eap_ttls_decode_pair(request_t *request, TALLOC_CTX *ctx, fr_dcursor_t *cursor, fr_dict_attr_t const *parent, uint8_t const *data, size_t data_len, void *decode_ctx)
#define FR_DIAMETER_AVP_FLAG_VENDOR
unsigned int code
Packet code (type).
fr_pair_t * fr_pair_list_head(fr_pair_list_t const *list)
Get the head of a valuepair list.
bool fr_pair_list_empty(fr_pair_list_t const *list)
Is a valuepair list empty.
fr_pair_t * fr_pair_list_next(fr_pair_list_t const *list, fr_pair_t const *item))
Get the next item in a valuepair list after a specific entry.
void fr_pair_list_free(fr_pair_list_t *list)
Free memory used by a valuepair list.
#define fr_pair_dcursor_init(_cursor, _list)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
ssize_t fr_value_box_from_network(TALLOC_CTX *ctx, fr_value_box_t *dst, fr_type_t type, fr_dict_attr_t const *enumv, fr_dbuff_t *dbuff, size_t len, bool tainted)
Decode a fr_value_box_t from serialized binary data.