26 RCSID(
"$Id: fbda2418d7687f942cd70f4ff82a5d3f5a90d1be $")
28 #include <freeradius-devel/util/dbuff.h>
29 #include <freeradius-devel/util/md5.h>
30 #include <freeradius-devel/util/struct.h>
31 #include <freeradius-devel/io/test_point.h>
32 #include <freeradius-devel/protocol/radius/freeradius.internal.h>
35 #define TAG_VALID(x) ((x) > 0 && (x) < 0x20)
65 if (len <
sizeof(passwd)) memset(passwd + len, 0,
sizeof(passwd) - len);
68 else if ((len & 0x0f) != 0) {
108 size_t output_len, encrypted_len, padding;
139 padding = encrypted_len - (
inlen + 1);
141 output_len = encrypted_len + 2;
157 if (((
size_t) -slen) > padding)
goto fail;
168 for (i = 3 +
inlen; i <
sizeof(tpasswd); i++) {
182 tpasswd[0] = (0x80 | (((packet_ctx->
salt_offset++) & 0x07) << 4) | ((r >> 8) & 0x0f));
183 tpasswd[1] = r & 0xff;
208 block_len = encrypted_len -
n;
211 for (i = 0; i < block_len; i++) tpasswd[i + 2 +
n] ^= digest[i];
245 if (!da_stack->
da[
depth + 1]) {
261 if (slen < 0)
return slen;
269 if (slen < 0)
return slen;
281 if ((da != da_stack->
da[
depth]) || (da_stack->
depth < da->depth))
break;
305 if (slen < 0)
return slen;
333 bool encrypted =
false;
359 if (slen <= 0)
return slen;
370 if (da_stack->
da[
depth + 1] != NULL) {
402 if (packet_ctx->
tag) {
412 value_dbuff =
FR_DBUFF(&work_dbuff);
417 switch (
vp->vp_type) {
422 if (
vp->vp_ip.af == AF_INET)
goto encode;
433 if (
vp->vp_ip.af == AF_INET)
goto ipv4_prefix;
462 if (slen <= 0)
return slen;
475 if (slen < 0)
return slen;
497 if (encrypt)
switch (encrypt) {
503 if (slen < 0)
return slen;
512 fr_strerror_const(
"Attributes with 'encrypt=Tunnel-Password' set cannot go into this packet.");
530 return slen - has_tag;
557 if (slen < 0)
return slen;
630 int flag_offset,
int vsa_offset)
632 unsigned int num_fragments, i = 0;
633 size_t max_frag_data =
UINT8_MAX - hdr_len;
640 if (num_fragments == 1)
return 0;
649 bool last = (i + 1) == num_fragments;
656 frag_len = (data_len - (max_frag_data * (num_fragments - 1)));
658 frag_len = max_frag_data;
689 "attr_fragment fragment %u/%u", i + 1, num_fragments);
803 da = da_stack->
da[my_depth];
812 if (slen <= 0)
return slen;
825 slen =
attr_fragment(&work_dbuff, (
size_t)vendor_hdr + slen, &hdr, 4, 3, 0);
826 if (slen <= 0)
return slen;
869 if (slen < 0)
return slen;
872 if (slen < 0)
return slen;
904 data_len =
vp->vp_length;
907 while (data_len > 0) {
921 data_len -= frag_len;
960 if (slen <= 0)
return slen;
1021 hdr_len = dv->flags.type_size + dv->flags.length;
1027 switch (dv->flags.type_size) {
1029 fr_strerror_printf(
"%s: Internal sanity check failed, type %u", __FUNCTION__, (
unsigned) dv->flags.type_size);
1048 switch (dv->flags.length) {
1050 fr_strerror_printf(
"%s: Internal sanity check failed, length %u", __FUNCTION__, (
unsigned) dv->flags.length);
1071 if (slen <= 0)
return slen;
1084 size_t length_offset = 0;
1086 if (dv->flags.length) length_offset = 6 + hdr_len - 1;
1088 slen =
attr_fragment(&work_dbuff, (
size_t)slen, &hdr, 6 + hdr_len, 0, length_offset);
1089 if (slen <= 0)
return slen;
1091 if (dv->flags.length) {
1152 if (slen <= 0)
return slen;
1165 slen =
attr_fragment(&work_dbuff, (
size_t)slen, &hdr, 9, 8, 7);
1166 if (slen <= 0)
return slen;
1208 if (da_stack->
da[
depth + 1]) {
1232 if (slen < 0)
return slen;
1266 if (da_stack->
da[
depth + 1]) {
1289 if (slen < 0)
return slen;
1314 size_t attr_len = 2;
1329 size_t data_len =
vp->vp_length;
1331 char const *p =
vp->vp_strvalue;
1336 while (data_len > 0) {
1337 frag_len = data_len;
1345 if ((attr_len + frag_len) <=
UINT8_MAX) {
1347 attr_len += frag_len;
1369 data_len -= frag_len;
1433 switch (da_stack->
da[
depth]->type) {
1478 "message-authenticator");
1543 (
vp->
da->attr > FR_TAG_BASE) && (
vp->
da->attr < (FR_TAG_BASE + 0x20))) {
1546 packet_ctx->
tag =
vp->
da->attr - FR_TAG_BASE;
1552 packet_ctx->
tag = 0;
1553 if (slen < 0)
return slen;
1562 switch (
vp->vp_type) {
1578 if ((
vp->vp_length == 0) &&
1598 switch (
vp->vp_type) {
1601 da_stack.
da[1] = NULL;
1605 if (slen < 0)
return slen;
1624 da = da_stack.
da[0];
1635 if (slen < 0)
return slen;
1642 if (slen < 0)
return slen;
1647 if (slen < 0)
return slen;
1654 }
else if (
vp->
da != da) {
1661 if (slen < 0)
return slen;
1675 fr_strerror_printf(
"%s: Nested attribute structure too large to encode", __FUNCTION__);
1686 .common = &common_ctx,
1705 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
1706 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
1712 if (!test_ctx)
return -1;
1716 common->
secret = talloc_strdup(test_ctx->
common,
"testing123");
1741 if (
vp) packet_type =
vp->vp_uint32;
1760 packet_ctx->
code = packet_type;
1767 if (slen <= 0)
return slen;
ssize_t fr_radius_encode_abinary(fr_pair_t const *vp, fr_dbuff_t *dbuff)
Encode a string to abinary.
#define FALL_THROUGH
clang 10 doesn't recognised the FALL-THROUGH comment anymore
#define fr_dbuff_advance(_dbuff_or_marker, _len)
Advance 'current' position in dbuff or marker by _len bytes.
#define fr_dbuff_used(_dbuff_or_marker)
Return the number of bytes remaining between the start of the dbuff or marker and the current positio...
#define FR_DBUFF_ABS(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
struct fr_dbuff_marker_s fr_dbuff_marker_t
A position marker associated with a dbuff.
#define fr_dbuff_current(_dbuff_or_marker)
Return the 'current' position of a dbuff or marker.
#define fr_dbuff_start(_dbuff_or_marker)
Return the 'start' position of a dbuff or marker.
#define fr_dbuff_set_to_start(_dbuff_or_marker)
Reset the 'current' position of the dbuff or marker to the 'start' of the buffer.
#define fr_dbuff_out_memcpy(_out, _dbuff_or_marker, _outlen)
Copy exactly _outlen bytes from the dbuff.
#define FR_DBUFF_BIND_CURRENT(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define FR_DBUFF_MEMSET_RETURN(_dbuff_or_marker, _c, _inlen)
Set _inlen bytes of a dbuff or marker to _c returning if there is insufficient space.
#define fr_dbuff_in_bytes(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker.
#define FR_DBUFF_IN_MEMCPY_RETURN(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into dbuff or marker returning if there's insufficient space.
#define fr_dbuff_in_memcpy(_dbuff_or_marker, _in, _inlen)
Copy exactly _inlen bytes into a dbuff or marker.
#define fr_dbuff_in(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff or marker.
#define FR_DBUFF_IN_RETURN(_dbuff_or_marker, _in)
Copy data from a fixed sized C type into a dbuff returning if there is insufficient space.
#define FR_DBUFF(_dbuff_or_marker)
Create a new dbuff pointing to the same underlying buffer.
#define FR_DBUFF_MAX(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
static uint8_t * fr_dbuff_marker(fr_dbuff_marker_t *m, fr_dbuff_t *dbuff)
Initialises a new marker pointing to the 'current' position of the dbuff.
#define FR_DBUFF_MAX_BIND_CURRENT(_dbuff_or_marker, _max)
Limit the maximum number of bytes available in the dbuff when passing it to another function.
#define fr_dbuff_out(_out, _dbuff_or_marker)
Copy data from a dbuff or marker to a fixed sized C type.
#define FR_DBUFF_IN_BYTES_RETURN(_dbuff_or_marker,...)
Copy a byte sequence into a dbuff or marker returning if there's insufficient space.
#define FR_DBUFF_TMP(_start, _len_or_end)
Creates a compound literal to pass into functions which accept a dbuff.
fr_dcursor_eval_t void const * uctx
static void * fr_dcursor_next(fr_dcursor_t *cursor)
Advanced the cursor to the next item.
static void * fr_dcursor_current(fr_dcursor_t *cursor)
Return the item the cursor current points to.
@ FR_RADIUS_CODE_ACCESS_REQUEST
RFC2865 - Access-Request.
@ FR_RADIUS_CODE_STATUS_SERVER
RFC2865/RFC5997 - Status Server (request)
static fr_dict_attr_t const * attr_packet_type
bool continuation
we only have one flag for now, for WiMAX
#define FR_DICT_MAX_TLV_STACK
Maximum TLV stack size.
fr_dict_vendor_t const * fr_dict_vendor_by_da(fr_dict_attr_t const *da)
Look up a vendor by one of its child attributes.
static uint32_t fr_dict_vendor_num_by_da(fr_dict_attr_t const *da)
Return the vendor number for an attribute.
Head of a doubly linked list.
#define PAIR_ENCODE_FATAL_ERROR
Fatal encoding error.
ssize_t fr_pair_ref_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor)
Encode a foreign reference to the network.
#define ROUND_UP_DIV(_x, _y)
Get the ceiling value of integer division.
#define ROUND_UP(_num, _mul)
Round up - Works in all cases, but is slower.
fr_md5_update_t fr_md5_update
fr_md5_final_t fr_md5_final
void fr_md5_ctx_free_from_list(fr_md5_ctx_t **ctx)
fr_md5_ctx_t * fr_md5_ctx_alloc_from_list(void)
fr_md5_ctx_copy_t fr_md5_ctx_copy
@ FR_TYPE_TLV
Contains nested attributes.
@ FR_TYPE_IPV6_PREFIX
IPv6 Prefix.
@ FR_TYPE_STRING
String of printable characters.
@ FR_TYPE_MAX
Number of defined data types.
@ FR_TYPE_NULL
Invalid (uninitialised) attribute type.
@ FR_TYPE_COMBO_IP_PREFIX
IPv4 or IPv6 address prefix depending on length.
@ FR_TYPE_UINT32
32 Bit unsigned integer.
@ FR_TYPE_STRUCT
like TLV, but without T or L, and fixed-width children
@ FR_TYPE_VENDOR
Attribute that represents a vendor in the attribute tree.
@ FR_TYPE_IPV6_ADDR
128 Bit IPv6 Address.
@ FR_TYPE_IPV4_PREFIX
IPv4 Prefix.
@ FR_TYPE_VSA
Vendor-Specific, for RADIUS attribute 26.
@ FR_TYPE_COMBO_IP_ADDR
IPv4 or IPv6 address depending on length.
@ FR_TYPE_OCTETS
Raw octets.
@ FR_TYPE_GROUP
A grouping of other attributes.
static uint8_t depth(fr_minmax_heap_index_t i)
static unsigned int fr_bytes_from_bits(unsigned int bits)
Convert bits (as in prefix length) to bytes, rounding up.
#define RADIUS_AUTH_VECTOR_LENGTH
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.
void fr_proto_da_stack_build(fr_da_stack_t *stack, fr_dict_attr_t const *da)
Build a complete DA stack from the da back to the root.
void * fr_proto_next_encodable(fr_dlist_head_t *list, void *current, void *uctx)
Implements the default iterator to encode pairs belonging to a specific dictionary that are not inter...
static fr_internal_encode_ctx_t encode_ctx
HIDDEN fr_dict_attr_t const * attr_packet_authentication_vector
HIDDEN fr_dict_attr_t const * attr_chargeable_user_identity
HIDDEN fr_dict_attr_t const * attr_nas_filter_rule
ssize_t fr_radius_ascend_secret(fr_dbuff_t *dbuff, uint8_t const *in, size_t inlen, char const *secret, uint8_t const *vector)
Do Ascend-Send / Recv-Secret calculation.
int fr_radius_sign(uint8_t *packet, uint8_t const *vector, uint8_t const *secret, size_t secret_len)
Sign a previously encoded packet.
ssize_t fr_radius_encode(fr_dbuff_t *dbuff, fr_pair_list_t *vps, fr_radius_encode_ctx_t *packet_ctx)
static ssize_t encode_vsa(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encode a Vendor-Specific attribute.
static ssize_t encode_wimax(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encode a WiMAX attribute.
static ssize_t encode_pairs(fr_dbuff_t *dbuff, fr_pair_list_t const *vps, void *encode_ctx)
static ssize_t encode_tunnel_password(fr_dbuff_t *dbuff, fr_dbuff_marker_t *in, size_t inlen, fr_radius_encode_ctx_t *packet_ctx)
void * fr_radius_next_encodable(fr_dlist_head_t *list, void *to_eval, void *uctx)
static ssize_t fr_radius_encode_proto(TALLOC_CTX *ctx, fr_pair_list_t *vps, uint8_t *data, size_t data_len, void *proto_ctx)
static ssize_t encode_value(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encodes the data portion of an attribute.
static ssize_t encode_concat(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, UNUSED void *encode_ctx)
Encode an RFC format attribute, with the "concat" flag set.
static ssize_t encode_extended(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, NDEBUG_UNUSED unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encode an "extended" attribute.
static ssize_t encode_extended_nested(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
static ssize_t encode_child(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encode an RFC format attribute.
ssize_t fr_radius_encode_pair(fr_dbuff_t *dbuff, fr_dcursor_t *cursor, void *encode_ctx)
Encode a data structure into a RADIUS attribute.
fr_test_point_pair_encode_t radius_tp_encode_pair
fr_test_point_proto_encode_t radius_tp_encode_proto
static ssize_t encode_tlv(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
ssize_t fr_radius_encode_foreign(fr_dbuff_t *dbuff, fr_pair_list_t const *list)
static int encode_test_ctx(void **out, TALLOC_CTX *ctx)
static ssize_t encode_password(fr_dbuff_t *dbuff, fr_dbuff_marker_t *input, size_t inlen, fr_radius_encode_ctx_t *packet_ctx)
"encrypt" a password RADIUS style
static ssize_t attr_fragment(fr_dbuff_t *data, size_t data_len, fr_dbuff_marker_t *hdr, size_t hdr_len, int flag_offset, int vsa_offset)
Breaks down large data into pieces, each with a header.
static ssize_t encode_nas_filter_rule(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, NDEBUG_UNUSED unsigned int depth, fr_dcursor_t *cursor, UNUSED void *encode_ctx)
Encode NAS-Filter-Rule.
static ssize_t encode_rfc(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encode an RFC standard attribute 1..255.
static ssize_t encode_vendor(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
static ssize_t encode_vendor_attr(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *cursor, void *encode_ctx)
Encode one full Vendor-Specific + Vendor-ID + Vendor-Attr + Vendor-Length + ...
static fr_dict_t const * dict_radius
bool secure_transport
for TLS
#define fr_radius_flag_concat(_da)
fr_fast_rand_t rand_ctx
for tunnel passwords
fr_radius_ctx_t const * common
#define fr_radius_flag_has_tag(_da)
bool disallow_tunnel_passwords
not all packets can have tunnel passwords
#define RADIUS_MAX_STRING_LENGTH
#define fr_radius_flag_encrypted(_da)
uint8_t const * request_authenticator
static bool fr_radius_flag_extended(fr_dict_attr_t const *da)
uint8_t tag
current tag for encoding
#define RADIUS_MESSAGE_AUTHENTICATOR_LENGTH
#define RADIUS_MAX_PASS_LENGTH
#define fr_radius_flag_long_extended(_da)
fr_radius_attr_flags_encrypt_t
@ RADIUS_FLAG_ENCRYPT_INVALID
Invalid encryption flag.
@ RADIUS_FLAG_ENCRYPT_NONE
No encryption.
@ RADIUS_FLAG_ENCRYPT_USER_PASSWORD
Encrypt attribute RFC 2865 style.
@ RADIUS_FLAG_ENCRYPT_ASCEND_SECRET
Encrypt attribute ascend style.
@ RADIUS_FLAG_ENCRYPT_TUNNEL_PASSWORD
Encrypt attribute RFC 2868 style.
int salt_offset
for tunnel passwords
#define fr_radius_flag_abinary(_da)
bool seen_message_authenticator
static fr_dict_attr_t const * attr_message_authenticator
uint32_t fr_fast_rand(fr_fast_rand_t *ctx)
uint32_t fr_rand(void)
Return a 32-bit random number.
static int encode(rlm_radius_udp_t const *inst, request_t *request, udp_request_t *u, uint8_t id)
ssize_t fr_struct_to_network(fr_dbuff_t *dbuff, fr_da_stack_t *da_stack, unsigned int depth, fr_dcursor_t *parent_cursor, void *encode_ctx, fr_encode_dbuff_t encode_value, fr_encode_dbuff_t encode_pair)
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.
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
fr_test_point_ctx_alloc_t test_ctx
Allocate a test ctx for the encoder.
Entry point for pair encoders.
Entry point for protocol encoders.
#define fr_pair_dcursor_iter_init(_cursor, _list, _iter, _uctx)
Initialises a special dcursor with callbacks that will maintain the attr sublists correctly.
static fr_pair_t * fr_pair_dcursor_child_iter_init(fr_dcursor_t *cursor, fr_pair_list_t const *list, fr_dcursor_t const *parent)
Initializes a child dcursor from a parent cursor, with an iteration function.
#define fr_pair_list_append_by_da_len(_ctx, _vp, _list, _attr, _val, _len, _tainted)
Append a pair to a list, assigning its value.
#define FR_PROTO_HEX_DUMP(_data, _data_len, _fmt,...)
#define FR_PROTO_STACK_PRINT(_stack, _depth)
uint8_t depth
Deepest attribute in the stack.
fr_dict_attr_t const * da[FR_DICT_MAX_TLV_STACK+1]
The stack.
Structure for holding the stack of dictionary attributes being encoded.
#define fr_strerror_printf(_fmt,...)
Log to thread local error buffer.
#define fr_strerror_const(_msg)
static char const * fr_type_to_str(fr_type_t type)
Return a static string containing the type name.
#define fr_type_is_structural(_x)
return fr_dbuff_set(dbuff, &our_dbuff)
ssize_t fr_value_box_to_network(fr_dbuff_t *dbuff, fr_value_box_t const *value)
Encode a single value box, serializing its contents in generic network format.
static size_t char fr_sbuff_t size_t inlen
static size_t char ** out