UNUSED void const *mod_inst, UNUSED void const *xlat_inst,
request_t *request, char const *fmt)
{
+ bool tainted = false;
char *data_name, *data_size, *data_type;
char *p;
size_t len, input_len;
int offset;
fr_type_t type;
fr_dict_attr_t const *da;
- fr_pair_t *vp, *cast;
+ fr_pair_t *vp;;
uint8_t const *input;
char buffer[256];
uint8_t blob[256];
* Attribute reference
*/
if (*data_name == '&') {
- if (xlat_fmt_get_vp(&vp, request, data_name) < 0) goto nothing;
+ fr_pair_t *from_vp;
- if ((vp->vp_type != FR_TYPE_OCTETS) &&
- (vp->vp_type != FR_TYPE_STRING)) {
+ if (xlat_fmt_get_vp(&from_vp, request, data_name) < 0) goto nothing;
+
+ if ((from_vp->vp_type != FR_TYPE_OCTETS) &&
+ (from_vp->vp_type != FR_TYPE_STRING)) {
REDEBUG("unpack requires the input attribute to be 'string' or 'octets'");
goto nothing;
}
- input = vp->vp_octets;
- input_len = vp->vp_length;
+ input = from_vp->vp_octets;
+ input_len = from_vp->vp_length;
+ tainted = from_vp->vp_tainted;
} else if ((data_name[0] == '0') && (data_name[1] == 'x')) {
/*
goto nothing;
}
} else {
- input = blob;
- input_len = 0;
+ GOTO_ERROR;
}
} else {
GOTO_ERROR;
offset = (int) strtoul(data_size, &p, 10);
if (*p) {
- REDEBUG("unpack requires a float64 number, not '%s'", data_size);
+ REDEBUG("unpack requires a decimal number, not '%s'", data_size);
goto nothing;
}
- type = fr_table_value_by_str(fr_value_box_type_table, data_type, FR_TYPE_INVALID);
- if (type == FR_TYPE_INVALID) {
- REDEBUG("Invalid data type '%s'", data_type);
+ if (offset >= input_len) {
+ REDEBUG("unpack offset %d is larger than input data length %zd", offset, input_len);
goto nothing;
}
- /*
- * Output must be a non-zero limited size.
- */
- if ((min_size(type) == 0) || !is_fixed_size(type)) {
- REDEBUG("unpack requires fixed-size output type, not '%s'", data_type);
- goto nothing;
- }
-
- if (input_len < (offset + min_size(type))) {
- REDEBUG("Insufficient data to unpack '%s' from '%s'", data_type, data_name);
+ type = fr_table_value_by_str(fr_value_box_type_table, data_type, FR_TYPE_INVALID);
+ if (type == FR_TYPE_INVALID) {
+ REDEBUG("Invalid data type '%s'", data_type);
goto nothing;
}
goto nothing;
}
- MEM(cast = fr_pair_afrom_da(request, da));
-
- memcpy(&(cast->data), input + offset, min_size(type));
+ MEM(vp = fr_pair_afrom_da(request, da));
/*
- * Hacks
+ * Call the generic routines to get data from the
+ * "network" buffer.
+ *
+ * @todo - just parse / print the value-box directly,
+ * instead of putting it into a VP.
+ *
+ * @todo - make this function 'async', and just return a
+ * copy of the value-box, instead of printing it to a string.
*/
- switch (type) {
- case FR_TYPE_INT32:
- case FR_TYPE_UINT32:
- cast->vp_uint32 = ntohl(cast->vp_uint32);
- break;
-
- case FR_TYPE_UINT16:
- cast->vp_uint16 = ((input[offset] << 8) | input[offset + 1]);
- break;
-
- case FR_TYPE_UINT64:
- cast->vp_uint64 = ntohll(cast->vp_uint64);
- break;
-
- case FR_TYPE_DATE:
- cast->vp_date = fr_time_from_timeval(&(struct timeval) {.tv_sec = ntohl(cast->vp_uint32)});
- break;
-
- default:
- break;
+ if (fr_value_box_from_network(vp, &vp->data, da->type, NULL, input + offset, input_len - offset, tainted) < 0) {
+ RPEDEBUG("Failed decoding %s", vp->da->name);
+ goto nothing;
}
- slen = fr_pair_print_value_quoted(&FR_SBUFF_OUT(*out, outlen), cast, T_BARE_WORD);
- talloc_free(cast);
+ slen = fr_pair_print_value_quoted(&FR_SBUFF_OUT(*out, outlen), vp, T_BARE_WORD);
+ talloc_free(vp);
if (slen < 0) {
REDEBUG("Insufficient buffer space to unpack data");
goto nothing;