26 RCSID(
"$Id: bd03c3da7b326b618cc5b029422639659d2c33e4 $")
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);
232 our_parent = attr_radius;
270 p += (value_len + 0x03) & ~0x03;
272 if (
vp->
da->flags.is_unknown)
continue;
291 static const char label[] =
"ttls challenge";
293 if ((
vp->vp_length < 8) || (
vp->vp_length > 16)) {
302 if (SSL_export_keying_material(ssl, challenge,
vp->vp_length + 1,
303 label,
sizeof(label) - 1, NULL, 0, 0) != 1) {
304 fr_tls_strerror_printf(
"Failed generating phase2 challenge");
308 if (memcmp(challenge,
vp->vp_octets,
vp->vp_length) != 0) {
360 if ((total +
vp->vp_length + 12) >=
sizeof(
buffer)) {
361 RDEBUG2(
"output buffer is full!");
370 length =
vp->vp_length;
373 attr =
vp->
da->attr & 0xffff;
386 memcpy(p, &attr,
sizeof(attr));
395 length = ntohl(length);
396 memcpy(p, &length,
sizeof(length));
400 vendor = ntohl(vendor);
401 memcpy(p, &vendor,
sizeof(vendor));
405 length = ntohl(length);
406 memcpy(p, &length,
sizeof(length));
411 switch (
vp->vp_type) {
414 memcpy(p, &attr,
sizeof(attr));
419 attr = htonl(
vp->vp_uint32);
420 memcpy(p, &attr,
sizeof(attr));
425 attr64 = htonll(
vp->vp_uint64);
426 memcpy(p, &attr64,
sizeof(attr64));
431 memcpy(p, &
vp->vp_ipv4addr, 4);
438 memcpy(p,
vp->vp_strvalue,
vp->vp_length);
439 length =
vp->vp_length;
452 if ((total & 0x03) != 0) {
455 length = 4 - (total & 0x03);
456 for (i = 0; i < length; i++) {
468 (tls_session->record_from_buff)(&tls_session->clean_in,
buffer, total);
473 fr_tls_session_send(request, tls_session);
489 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
519 switch (reply->
code) {
521 RDEBUG2(
"Got tunneled Access-Accept");
528 RDEBUG2(
"Got MS-CHAP2-Success, tunneling it to the client in a challenge");
545 REDEBUG(
"Got tunneled Access-Reject");
556 RDEBUG2(
"Got tunneled Access-Challenge");
573 REDEBUG(
"Unknown RADIUS packet type %d: rejecting tunneled user", reply->
code);
584 RDEBUG2(
"Sending tunneled reply attributes");
598 fr_tls_session_t *tls_session = eap_tls_session->
tls_session;
602 "ttls keying material",
603 sizeof(
"ttls keying material") - 1);
627 return fr_tls_cache_pending_push(request, tls_session);
647 data_len = tls_session->clean_out.used;
648 tls_session->clean_out.used = 0;
649 data = tls_session->clean_out.data;
659 RDEBUG2(
"Got ACK, and the user was already authenticated");
677 data, data_len, tls_session->ssl) < 0) {
678 RPEDEBUG(
"Decoding TTLS TLVs failed");
709 (
char const *)
vp->vp_octets + 5,
vp->vp_length - 5,
true);
718 RWDEBUG2(
"No EAP-Identity found to start EAP conversation");
736 RDEBUG2(
"received chbind request");
747 RDEBUG2(
"sending chbind response");
unlang_action_t
Returned by unlang_op_t calls, determine the next action of the interpreter.
@ UNLANG_ACTION_FAIL
Encountered an unexpected error.
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.
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.
static fr_dict_attr_t * fr_dict_attr_unknown_vendor_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int vendor)
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.
static fr_dict_attr_t * fr_dict_attr_unknown_raw_afrom_num(TALLOC_CTX *ctx, fr_dict_attr_t const *parent, unsigned int attr)
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.
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
void eap_crypto_prf_label_init(eap_tls_prf_label_t *prf_label, eap_session_t *eap_session, char const *keying_prf_label, size_t keying_prf_label_len)
Initialize the PRF label fields.
Declarations for EAP-TTLS as defined by RFC 5281.
HIDDEN fr_dict_attr_t const * attr_reply_message
HIDDEN fr_dict_attr_t const * attr_eap_channel_binding_message
HIDDEN fr_dict_attr_t const * attr_eap_message
unlang_action_t eap_virtual_server(request_t *request, eap_session_t *eap_session, CONF_SECTION *server_cs)
Run a subrequest through a virtual server.
void * opaque
Opaque data used by EAP methods.
request_t * request
Current request.
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.
void * rctx
Resume ctx that a module previously set.
Temporary structure to hold arguments for module calls.
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_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_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.
fr_pair_t * fr_pair_afrom_da_nested(TALLOC_CTX *ctx, fr_pair_list_t *list, fr_dict_attr_t const *da)
Create a pair (and all intermediate parents), and append it to the list.
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.
fr_pair_t * fr_pair_copy(TALLOC_CTX *ctx, fr_pair_t const *vp)
Copy a single valuepair.
fr_pair_t * fr_pair_find_by_da_nested(fr_pair_list_t const *list, fr_pair_t const *prev, fr_dict_attr_t const *da)
Find a pair with a matching fr_dict_attr_t, by walking the nested fr_dict_attr_t tree.
int fr_pair_value_strtrim(fr_pair_t *vp)
Trim the length of the string buffer to match the length of the C string.
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
#define RETURN_MODULE_REJECT
#define RETURN_MODULE_INVALID
rlm_rcode_t
Return codes indicating the result of the module call.
@ RLM_MODULE_OK
The module is OK, continue.
static fr_dict_attr_t const * attr_ms_chap2_success
unlang_action_t unlang_module_yield(request_t *request, module_method_t resume, unlang_module_signal_t signal, fr_signal_t sigmask, void *rctx)
Yield a request back to the interpreter from within a module.
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)
int eap_tls_success(request_t *request, eap_session_t *eap_session, eap_tls_prf_label_t *prf_label)
Send an EAP-TLS success.
int eap_tls_request(request_t *request, eap_session_t *eap_session)
Frames the OpenSSL data that needs to be sent to the client in an EAP-Request.
int eap_tls_fail(request_t *request, eap_session_t *eap_session)
Send an EAP-TLS failure.
fr_tls_session_t * tls_session
TLS session used to authenticate peer or tunnel sensitive data.
Tracks the state of an EAP-TLS session.
unlang_action_t eap_ttls_process(request_t *request, eap_session_t *eap_session, fr_tls_session_t *tls_session)
#define FR_DIAMETER_AVP_FLAG_MANDATORY
static unlang_action_t process_reply(rlm_rcode_t *p_result, module_ctx_t const *mctx, request_t *request)
unlang_action_t eap_ttls_success(rlm_rcode_t *p_result, request_t *request, eap_session_t *eap_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_pair_list_t *out, 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_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.
static size_t char ** out