*/
if (unlikely(inlen % 4)) {
fr_strerror_printf("%s: Input data length is not a multiple of 4", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
total_len = (inlen + (block_size - 1)) & ~(block_size - 1); /* Round input length to block size (16) */
evp_ctx = EVP_CIPHER_CTX_new();
if (!evp_ctx) {
tls_strerror_printf("Failed allocating EVP context");
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
if (unlikely(EVP_EncryptInit_ex(evp_ctx, evp_cipher, NULL,
error:
talloc_free(encr);
EVP_CIPHER_CTX_free(evp_ctx);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
encr = talloc_array(NULL, uint8_t, total_len);
if (unlikely(tlv_stack[depth + 1] != NULL)) {
fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
if (unlikely(vp->da != da)) {
fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
switch (da->type) {
case FR_TYPE_STRUCTURAL:
fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
fr_table_str_by_value(fr_value_box_type_table, tlv_stack[depth]->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
default:
break;
fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
"but value was %zu bytes", __FUNCTION__,
da->name, (size_t)da->flags.length, vp->vp_length);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
memcpy(packet_ctx->iv, vp->vp_octets, sizeof(packet_ctx->iv));
packet_ctx->iv_included = true;
if ((vp->vp_length < 4) || (vp->vp_length > 16)) {
fr_strerror_printf("%s: AKA-RES Length must be between 4-16 bytes, got %zu bytes",
__FUNCTION__, vp->vp_length);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
CHECK_FREESPACE(outlen, vp->vp_length + 2);
fr_strerror_printf("%s: Attribute \"%s\" needs a value of exactly %zu bytes, "
"but value was %zu bytes", __FUNCTION__,
vp->da->name, (size_t)vp->da->flags.length, vp->vp_length);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
memcpy(p, &actual_len, sizeof(actual_len)); /* Big endian real string length */
fr_strerror_printf("%s: Attribute \"%s\" needs a value of <= %zu bytes, "
"but value was %zu bytes", __FUNCTION__,
vp->da->name, (size_t)vp->da->flags.length, vp->vp_length);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
/*
default:
fr_strerror_printf("%s: Cannot encode attribute %s", __FUNCTION__, vp->da->name);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
done:
if (!da->flags.length) {
fr_strerror_printf("Can't encode array type attribute \"%s\" as it does not "
"have a fixed length", da->name);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
element_len = da->flags.length;
} else {
case FR_TYPE_STRUCTURAL:
fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
fr_table_str_by_value(fr_value_box_type_table, tlv_stack[depth]->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
default:
if (((fr_dict_vendor_num_by_da(tlv_stack[depth]) == 0) && (tlv_stack[depth]->attr == 0)) ||
(tlv_stack[depth]->attr > 255)) {
fr_strerror_printf("%s: Called with non-standard attribute %u", __FUNCTION__,
tlv_stack[depth]->attr);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
break;
}
*/
if (!da->flags.extra && da->flags.subtype) {
slen = encode_encrypted_value(value, end - value, value, p - value, encoder_ctx);
- if (slen < 0) return PAIR_ENCODE_ERROR;
+ if (slen < 0) return PAIR_ENCODE_FATAL_ERROR;
p = value + slen;
}
if (tlv_stack[depth]->type != FR_TYPE_TLV) {
fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
fr_table_str_by_value(fr_value_box_type_table, tlv_stack[depth]->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
if (!tlv_stack[depth + 1]) {
fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
/*
fr_dict_attr_t const *da = NULL;
fr_aka_sim_encode_ctx_t *packet_ctx = encoder_ctx;
- if (!cursor || !out) return PAIR_ENCODE_ERROR;
+ if (!cursor || !out) return PAIR_ENCODE_FATAL_ERROR;
CHECK_FREESPACE(outlen, 4); /* Attributes lengths are always multiples of 4 */
if (vp->da->depth > FR_DICT_MAX_TLV_STACK) {
fr_strerror_printf("%s: Attribute depth %i exceeds maximum nesting depth %i",
__FUNCTION__, vp->da->depth, FR_DICT_MAX_TLV_STACK);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
if (vp->da->attr == FR_MAC) {
*/
if (fr_cursor_current(cursor) == vp) {
fr_strerror_printf("%s: Nested attribute structure too large to encode", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
return slen;
vp = fr_pair_find_by_child_num(to_encode, packet_ctx->root, FR_SUBTYPE, TAG_ANY);
if (!vp) {
REDEBUG("Missing subtype attribute");
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
subtype = vp->vp_uint16;
if (slen < 0) {
error:
talloc_free(buff);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
p += slen;
rad_assert(p < end); /* We messed up a check somewhere in the encoder */
* @file io/pair.h
* @brief Encoder/decoder library interface
*
- * @copyright 2017 The FreeRADIUS project
+ * @copyright 2017-2020 The FreeRADIUS project
*/
#include <freeradius-devel/util/value.h>
-#define PAIR_ENCODE_SKIP SSIZE_MIN + 1
-#define PAIR_ENCODE_ERROR SSIZE_MIN
+/** @name Encoder errors
+ * @{
+ */
+
+/** Encoder skipped encoding an attribute
+ */
+#define PAIR_ENCODE_SKIPPED SSIZE_MIN + 1
+
+/** Skipped encoding attribute
+ */
+#define PAIR_ENCODE_FATAL_ERROR SSIZE_MIN
+
+/** @} */
+
+/** @name Decode errors
+ * @{
+ */
+
+/** Fatal error - Out of memory
+ */
+#define PAIR_DECODE_OOM SSIZE_MIN + 1
+
+/** Fatal error - Failed decoding the packet
+ */
+#define PAIR_DECODE_FATAL_ERROR SSIZE_MIN
+
+/** @} */
/** Generic interface for encoding one or more VALUE_PAIRs
*
* @param[in] cursor Cursor containing the list of attributes to process.
* @param[in] encoder_ctx Any encoder specific data such as secrets or configurables.
* @return
- * - PAIR_ENCODE_SKIP - The current pair is not valid for encoding and should be skipped.
- * - PAIR_ENCODE_ERROR - Encoding failed in a fatal way. Encoding the packet should be
+ * - PAIR_ENCODE_SKIPPED - The current pair is not valid for encoding and should be skipped.
+ * - PAIR_ENCODE_FATAL_ERROR - Encoding failed in a fatal way. Encoding the packet should be
* aborted in its entirety.
* - <0 - The encoder ran out of space and returned the number of bytes as a negative
* integer that would be required to encode the attribute.
while ((p < end) && (fr_cursor_current(&cursor) != NULL)) {
slen = fr_dhcpv6_encode_option(p, end - p, &cursor, &packet_ctx);
- if (slen == PAIR_ENCODE_SKIP) continue;
+ if (slen == PAIR_ENCODE_SKIPPED) continue;
if (slen < 0) return slen - (p - packet);
if (!fr_cond_assert_msg(parent->flags.array,
"%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
- __FUNCTION__, parent->name)) return PAIR_ENCODE_ERROR;
+ __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
/*
* Fixed-size fields get decoded with a simple decoder.
if (!fr_cond_assert_msg((parent->type == FR_TYPE_TLV || (parent->type == FR_TYPE_VENDOR)),
"%s: Internal sanity check failed, attribute \"%s\" is not of type 'tlv'",
- __FUNCTION__, parent->name)) return PAIR_ENCODE_ERROR;
+ __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
p = data;
end = data + data_len;
if (!fr_cond_assert_msg(parent->type == FR_TYPE_VSA,
"%s: Internal sanity check failed, attribute \"%s\" is not of type 'vsa'",
- __FUNCTION__, parent->name)) return PAIR_ENCODE_ERROR;
+ __FUNCTION__, parent->name)) return PAIR_DECODE_FATAL_ERROR;
/*
* Enterprise code plus at least one option header
if (tlv_stack[depth]->type != FR_TYPE_STRUCT) {
fr_strerror_printf("%s: Expected type \"struct\" got \"%s\"", __FUNCTION__,
fr_table_str_by_value(fr_value_box_type_table, tlv_stack[depth]->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
if (!tlv_stack[depth + 1]) {
fr_strerror_printf("%s: Can't encode empty struct", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
return fr_struct_to_network(out, outlen, tlv_stack, depth, cursor, encoder_ctx, encode_value);
*/
if (tlv_stack[depth + 1] != NULL) {
fr_strerror_printf("%s: Encoding value but not at top of stack", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
if (vp->da != da) {
fr_strerror_printf("%s: Top of stack does not match vp->da", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
switch (da->type) {
case FR_TYPE_STRUCTURAL:
fr_strerror_printf("%s: Called with structural type %s", __FUNCTION__,
fr_table_str_by_value(fr_value_box_type_table, da->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
default:
break;
/*
* @todo - check for free space, etc.
*/
- if (slen <= 0) return PAIR_ENCODE_ERROR;
+ if (slen <= 0) return PAIR_ENCODE_FATAL_ERROR;
/*
* RFC 4704 says "FQDN", unless it's a
case FR_TYPE_TIME_DELTA:
CHECK_FREESPACE(outlen, fr_dhcpv6_option_len(vp));
slen = fr_value_box_to_network(NULL, p, end - p, &vp->data);
- if (slen < 0) return PAIR_ENCODE_ERROR;
+ if (slen < 0) return PAIR_ENCODE_FATAL_ERROR;
p += slen;
break;
while (fr_cursor_current(&child_cursor) != NULL) {
child = fr_cursor_current(&child_cursor);
slen = fr_dhcpv6_encode_option(p, end - p, &child_cursor, encoder_ctx);
- if (slen == PAIR_ENCODE_SKIP) continue;
+ if (slen == PAIR_ENCODE_SKIPPED) continue;
- if (slen < 0) return PAIR_ENCODE_ERROR;
+ if (slen < 0) return PAIR_ENCODE_FATAL_ERROR;
if (slen == 0) break;
p += slen;
case FR_TYPE_MAX:
fr_strerror_printf("Unsupported attribute type %s",
fr_table_str_by_value(fr_value_box_type_table, da->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
/*
if (!fr_cond_assert_msg(da->flags.array,
"%s: Internal sanity check failed, attribute \"%s\" does not have array bit set",
- __FUNCTION__, da->name)) return PAIR_ENCODE_ERROR;
+ __FUNCTION__, da->name)) return PAIR_ENCODE_FATAL_ERROR;
/*
* DNS labels have internalized length, so we don't need
* https://tools.ietf.org/html/rfc8415#section-10
*/
slen = fr_dns_label_from_value_box(NULL, out, outlen, p, false, &vp->data);
- if (slen <= 0) return PAIR_ENCODE_ERROR;
+ if (slen <= 0) return PAIR_ENCODE_FATAL_ERROR;
p += slen;
vp = next_encodable(cursor, encoder_ctx);
slen = encode_value(p, end - p, tlv_stack, depth, cursor, encoder_ctx);
if (slen < 0) return slen;
- if (!fr_cond_assert(slen < UINT16_MAX)) return PAIR_ENCODE_ERROR;
+ if (!fr_cond_assert(slen < UINT16_MAX)) return PAIR_ENCODE_FATAL_ERROR;
/*
* Ensure we always create elements of the correct length.
if (tlv_stack[depth]->type != FR_TYPE_TLV) {
fr_strerror_printf("%s: Expected type \"tlv\" got \"%s\"", __FUNCTION__,
fr_table_str_by_value(fr_value_box_type_table, tlv_stack[depth]->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
if (!tlv_stack[depth + 1]) {
fr_strerror_printf("%s: Can't encode empty TLV", __FUNCTION__);
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
CHECK_FREESPACE(outlen, OPT_HDR_LEN);
if (da->type != FR_TYPE_VSA) {
fr_strerror_printf("%s: Expected type \"vsa\" got \"%s\"", __FUNCTION__,
fr_table_str_by_value(fr_value_box_type_table, da->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
/*
if (dv->type != FR_TYPE_VENDOR) {
fr_strerror_printf("%s: Expected type \"vsa\" got \"%s\"", __FUNCTION__,
fr_table_str_by_value(fr_value_box_type_table, dv->type, "?Unknown?"));
- return PAIR_ENCODE_ERROR;
+ return PAIR_ENCODE_FATAL_ERROR;
}
/*
if (vp->da->flags.internal) {
fr_strerror_printf("Attribute \"%s\" is not a DHCPv6 option", vp->da->name);
fr_cursor_next(cursor);
- return PAIR_ENCODE_SKIP;
+ return PAIR_ENCODE_SKIPPED;
}
fr_proto_tlv_stack_build(tlv_stack, vp->da);