/*
* Hex encoding, consume three chars
*/
- if (fr_hex2bin(&FR_DBUFF_TMP((uint8_t *) &c, 1), &FR_SBUFF_IN(p + 1, 2)) == 1) {
+ if (fr_hex2bin(NULL, &FR_DBUFF_TMP((uint8_t *) &c, 1), &FR_SBUFF_IN(p + 1, 2), false) == 1) {
inlen -= 2;
p += 2;
continue;
* special encoding, get rewritten to the
* special encoding.
*/
- if (fr_hex2bin(&FR_DBUFF_TMP((uint8_t *) &c, 1), &FR_SBUFF_IN(p + 1, 2)) == 1) {
+ if (fr_hex2bin(NULL, &FR_DBUFF_TMP((uint8_t *) &c, 1), &FR_SBUFF_IN(p + 1, 2), false) == 1) {
switch (c) {
case ' ':
case '#':
hex_len = talloc_array_length(value) - 3;
bin_len = (hex_len / 2) + 1;
MEM(bin = talloc_array(c, uint8_t, bin_len));
- converted = fr_hex2bin(&FR_DBUFF_TMP(bin, bin_len), &FR_SBUFF_IN(value + 2, hex_len));
+ converted = fr_hex2bin(NULL,
+ &FR_DBUFF_TMP(bin, bin_len),
+ &FR_SBUFF_IN(value + 2, hex_len), false);
if (converted < (bin_len - 1)) {
cf_log_err(cs, "Invalide hex string in shared secret");
goto error;
ptr = talloc_array(map, uint8_t, len >> 1);
if (!ptr) return false;
- fr_hex2bin(&FR_DBUFF_TMP(ptr, len >> 1), &FR_SBUFF_IN(rhs + 2, len));
+ fr_hex2bin(NULL, &FR_DBUFF_TMP(ptr, len >> 1), &FR_SBUFF_IN(rhs + 2, len), false);
/*
* Convert to da->type (if possible);
if (!(len & 0x01) && len >= (2 * min_len)) {
size_t decoded;
- decoded = fr_hex2bin(&FR_DBUFF_TMP(buffer, bufflen), &FR_SBUFF_IN(known_good, len));
+ decoded = fr_hex2bin(NULL, &FR_DBUFF_TMP(buffer, bufflen), &FR_SBUFF_IN(known_good, len), false);
if (decoded == (len >> 1)) {
if (action) *action = NORMALISED_HEX;
return decoded;
vpt = tmpl_alloc(ctx, TMPL_TYPE_DATA, in, inlen, type);
(void)fr_value_box_mem_alloc(vpt, &bin, &vpt->data.literal, NULL, binlen, false);
- len = fr_hex2bin(&FR_DBUFF_TMP(bin, binlen), &FR_SBUFF_IN(in + 2, inlen - 2));
+ len = fr_hex2bin(NULL, &FR_DBUFF_TMP(bin, binlen), &FR_SBUFF_IN(in + 2, inlen - 2), false);
if (len != binlen) {
fr_strerror_printf("Hex string contains non-hex char");
talloc_free(vpt);
/*
* If hex2bin returns 0 the next two chars weren't hexits.
*/
- if (fr_hex2bin(&FR_DBUFF_TMP((uint8_t *) out, 1), &FR_SBUFF_IN(in, 1)) == 0) return in - (p + 1);
+ if (fr_hex2bin(NULL,
+ &FR_DBUFF_TMP((uint8_t *) out, 1),
+ &FR_SBUFF_IN(in, 1), false) == 0) return in - (p + 1);
in += 2;
out++;
freespace--;
* Check the password now, so that we don't have
* errors at run-time.
*/
- hex_len = fr_hex2bin(&FR_DBUFF_TMP(buffer, sizeof(buffer)), &FR_SBUFF_IN(conf->psk_password, psk_len));
+ hex_len = fr_hex2bin(NULL,
+ &FR_DBUFF_TMP(buffer, sizeof(buffer)),
+ &FR_SBUFF_IN(conf->psk_password, psk_len), false);
if (psk_len != (2 * hex_len)) {
ERROR("psk_hexphrase is not all hex");
goto error;
strlcpy(identity, conf->psk_identity, max_identity_len);
- return fr_hex2bin(&FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len),
- &FR_SBUFF_IN(conf->psk_password, (size_t)psk_len));
+ return fr_hex2bin(NULL,
+ &FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len),
+ &FR_SBUFF_IN(conf->psk_password, (size_t)psk_len), false);
}
/** Determine the PSK to use for an incoming connection
* convert the expansion from printable string
* back to hex.
*/
- return fr_hex2bin(&FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len), &FR_SBUFF_IN(buffer, hex_len));
+ return fr_hex2bin(NULL,
+ &FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len),
+ &FR_SBUFF_IN(buffer, hex_len), false);
}
if (!conf->psk_identity) {
psk_len = strlen(conf->psk_password);
if (psk_len > (2 * max_psk_len)) return 0;
- return fr_hex2bin(&FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len), &FR_SBUFF_IN(conf->psk_password, psk_len));
+ return fr_hex2bin(NULL,
+ &FR_DBUFF_TMP((uint8_t *)psk, (size_t)max_psk_len),
+ &FR_SBUFF_IN(conf->psk_password, psk_len), false);
}
#endif /* PSK_MAX_IDENTITY_LEN */
REQUEST *request, UNUSED void const *xlat_inst, UNUSED void *xlat_thread_inst,
fr_value_box_t **in)
{
- fr_value_box_t *result;
- char *buff = NULL, *p, *end;
- uint8_t *bin;
- size_t len, outlen;
+ fr_value_box_t *result;
+ char *buff = NULL, *p, *end;
+ uint8_t *bin;
+ size_t len, outlen;
+ fr_sbuff_parse_error_t err;
/*
* If there's no input, there's no output
MEM(result = fr_value_box_alloc_null(ctx));
MEM(fr_value_box_mem_alloc(result, &bin, result, NULL, outlen, fr_value_box_list_tainted(*in)) == 0);
- fr_hex2bin(&FR_DBUFF_TMP(bin, outlen), &FR_SBUFF_IN(p, end - p));
+ fr_hex2bin(&err, &FR_DBUFF_TMP(bin, outlen), &FR_SBUFF_IN(p, end - p), true);
+ if (err) {
+ REDEBUG2("Invalid hex string");
+ talloc_free(result);
+ return XLAT_ACTION_FAIL;
+ }
fr_cursor_append(out, result);
/*
* Node must be 6 octets long.
*/
- token = fr_hex2bin(&FR_DBUFF_TMP(net->node, IPX_NODE_ADDR_LEN), &FR_SBUFF_IN(p, strlen(p)));
+ token = fr_hex2bin(NULL,
+ &FR_DBUFF_TMP(net->node, IPX_NODE_ADDR_LEN),
+ &FR_SBUFF_IN(p, strlen(p)), false);
if (token != IPX_NODE_ADDR_LEN) return -1;
/*
filter->offset = rcode;
filter->offset = htons(filter->offset);
- rcode = fr_hex2bin(&FR_DBUFF_TMP(filter->mask, sizeof(filter->mask)), &FR_SBUFF_IN(argv[1], strlen(argv[1])));
+ rcode = fr_hex2bin(NULL,
+ &FR_DBUFF_TMP(filter->mask, sizeof(filter->mask)),
+ &FR_SBUFF_IN(argv[1], strlen(argv[1])), false);
if (rcode != sizeof(filter->mask)) return -1;
- token = fr_hex2bin(&FR_DBUFF_TMP(filter->value, sizeof(filter->value)), &FR_SBUFF_IN(argv[2], strlen(argv[2])));
+ token = fr_hex2bin(NULL,
+ &FR_DBUFF_TMP(filter->value, sizeof(filter->value)),
+ &FR_SBUFF_IN(argv[2], strlen(argv[2])), false);
if (token != sizeof(filter->value)) return -1;
filter->len = rcode;
/** Convert hex strings to binary data
*
- * @param[out] out Output buffer to write to.
- * @param[in] in Input string.
+ * @param[out] err If non-null contains any parse errors.
+ * @param[out] out Output buffer to write to.
+ * @param[in] in Input string.
+ * @param[in] no_trailing Error and return 0 if we find an odd length hex
+ * string.
* @return
* - >=0 the number of bytes written to out.
+ * - 0 no input data, or parse error.
* - <0 number of bytes we would have needed to copy the next hexit.
*/
-ssize_t fr_hex2bin(fr_dbuff_t *out, fr_sbuff_t *in)
+ssize_t fr_hex2bin(fr_sbuff_parse_error_t *err, fr_dbuff_t *out, fr_sbuff_t *in, bool no_trailing)
{
- size_t total = 0;
+ size_t total = 0;
+ fr_sbuff_t our_in = FR_SBUFF_NO_ADVANCE(in);
+ fr_dbuff_t our_out = FR_DBUFF_NO_ADVANCE(out);
- while (!FR_SBUFF_CANT_EXTEND_LOWAT(in, 2)) {
+ while (!FR_SBUFF_CANT_EXTEND_LOWAT(&our_in, 2)) {
char *c1, *c2;
- if(!(c1 = memchr(hextab, tolower((int) *in->p), sizeof(hextab))) ||
- !(c2 = memchr(hextab, tolower((int) *(in->p + 1)), sizeof(hextab)))) break;
+ if(!(c1 = memchr(hextab, tolower((int) *our_in.p), sizeof(hextab))) ||
+ !(c2 = memchr(hextab, tolower((int) *(our_in.p + 1)), sizeof(hextab)))) {
+ if (!c2 && no_trailing) {
+ got_trailing:
+ if (err) *err = FR_SBUFF_PARSE_ERROR_TRAILING;
+ return 0;
+ }
+ goto done;
+ }
- FR_DBUFF_BYTES_IN_RETURN(out, ((c1 - hextab) << 4) + (c2 - hextab));
+ FR_DBUFF_BYTES_IN_RETURN(&our_out, ((c1 - hextab) << 4) + (c2 - hextab));
- fr_sbuff_advance(in, 2);
+ fr_sbuff_advance(&our_in, 2);
total++;
};
+ if (no_trailing && (fr_sbuff_remaining(&our_in) > 0) &&
+ memchr(hextab, tolower((int) *our_in.p), sizeof(hextab))) goto got_trailing;
+
+done:
+ fr_sbuff_set(in, &our_in);
+ fr_dbuff_set(out, &our_out);
+
+ if (err) *err = FR_SBUFF_PARSE_OK;
+
return total;
}
#include <freeradius-devel/util/sbuff.h>
#include <freeradius-devel/util/dbuff.h>
-ssize_t fr_hex2bin(fr_dbuff_t *out, fr_sbuff_t *in);
+ssize_t fr_hex2bin(fr_sbuff_parse_error_t *err, fr_dbuff_t *out, fr_sbuff_t *in, bool no_trailing);
ssize_t fr_bin2hex(fr_sbuff_t *out, fr_dbuff_t *in);
if (_match_len) *(_match_len) = _match_len_tmp; \
} while (0)
+/** Build a talloc wrapper function for a fr_sbuff_out_* function
+ *
+ * @param[in] _func to call.
+ * @param[in] _in input sbuff arg.
+ * @param[in] _len expected output len.
+ * @param[in] ... additional arguments to pass to _func.
+ */
+#define SBUFF_OUT_TALLOC_ERR_FUNC_DEF(_func, _in, _len, ...) \
+{ \
+ fr_sbuff_t sbuff; \
+ fr_sbuff_uctx_talloc_t tctx; \
+ fr_sbuff_parse_error_t err; \
+ ssize_t slen; \
+ fr_sbuff_init_talloc(ctx, &sbuff, &tctx, \
+ ((_len) != SIZE_MAX) ? (_len) : 1024, \
+ ((_len) != SIZE_MAX) ? (_len) : SIZE_MAX); \
+ slen = _func(&err, &sbuff, _in, _len, ##__VA_ARGS__); \
+ if (slen <= 0) { \
+ if (err != FR_SBUFF_PARSE_OK) { \
+ TALLOC_FREE(sbuff.buff); \
+ } else { \
+ fr_sbuff_trim_talloc(&sbuff, 0); \
+ } \
+ *out = sbuff.buff; \
+ return 0; \
+ } \
+ fr_sbuff_trim_talloc(&sbuff, SIZE_MAX); \
+ *out = sbuff.buff; \
+ return (size_t)slen; \
+}
+
/** Build a talloc wrapper function for a fr_sbuff_out_* function
*
* @param[in] _func to call.
ret = len >> 1;
p = talloc_array(ctx, uint8_t, ret);
- if (fr_hex2bin(&FR_DBUFF_TMP(p, ret), &FR_SBUFF_IN(in + 2, len)) != (ssize_t)ret) {
+ if (fr_hex2bin(NULL, &FR_DBUFF_TMP(p, ret), &FR_SBUFF_IN(in + 2, len), false) != (ssize_t)ret) {
talloc_free(p);
fr_strerror_printf("Invalid hex data");
return -1;
return -1;
}
- bin = fr_hex2bin(&FR_DBUFF_TMP((uint8_t *) &dst->datum.filter, (len - 2) / 2), &FR_SBUFF_IN(in + 2, len - 2));
+ bin = fr_hex2bin(NULL, &FR_DBUFF_TMP((uint8_t *) &dst->datum.filter, (len - 2) / 2),
+ &FR_SBUFF_IN(in + 2, len - 2), false);
if (bin < ret) {
memset(((uint8_t *) &dst->datum.filter) + bin, 0, ret - bin);
}
return -1;
}
- return fr_hex2bin(&FR_DBUFF_TMP(secret, BFD_MAX_SECRET_LENGTH), &FR_SBUFF_IN(value + 2, (len - 2)));
+ return fr_hex2bin(NULL, &FR_DBUFF_TMP(secret, BFD_MAX_SECRET_LENGTH),
+ &FR_SBUFF_IN(value + 2, (len - 2)), false);
}
if (len >= 20) {
* Set A1 to Digest-HA1 if no User-Password found
*/
if (passwd->da == attr_digest_ha1) {
- if (fr_hex2bin(&FR_DBUFF_TMP(&a1[0], sizeof(a1)), &FR_SBUFF_IN(passwd->vp_strvalue, passwd->vp_length)) != 16) {
+ if (fr_hex2bin(NULL, &FR_DBUFF_TMP(&a1[0], sizeof(a1)),
+ &FR_SBUFF_IN(passwd->vp_strvalue, passwd->vp_length), false) != 16) {
RDEBUG2("Invalid text in Digest-HA1");
return RLM_MODULE_INVALID;
}
return RLM_MODULE_INVALID;
}
- if (fr_hex2bin(&FR_DBUFF_TMP(&hash[0], sizeof(hash)),
- &FR_SBUFF_IN(vp->vp_strvalue, vp->vp_length)) != (ssize_t)(vp->vp_length >> 1)) {
+ if (fr_hex2bin(NULL, &FR_DBUFF_TMP(&hash[0], sizeof(hash)),
+ &FR_SBUFF_IN(vp->vp_strvalue, vp->vp_length), false) != (ssize_t)(vp->vp_length >> 1)) {
RDEBUG2("Invalid text in Digest-Response");
return RLM_MODULE_INVALID;
}
if (n == 3) {
RDEBUG2("Found new challenge from MS-CHAP-Error: err=%d retry=%d challenge=%s",
err, retry, buf);
- fr_hex2bin(&FR_DBUFF_TMP(data->auth_challenge, 16), &FR_SBUFF_IN(buf, strlen(buf)));
+ fr_hex2bin(NULL, &FR_DBUFF_TMP(data->auth_challenge, 16),
+ &FR_SBUFF_IN(buf, strlen(buf)), false);
} else {
RDEBUG2("Could not parse new challenge from MS-CHAP-Error: %d", n);
}
/*
* Update the NT hash hash, from the NT key.
*/
- if (fr_hex2bin(&FR_DBUFF_TMP(nthashhash, NT_DIGEST_LENGTH), &FR_SBUFF_IN(buffer + 8, len)) != NT_DIGEST_LENGTH) {
+ if (fr_hex2bin(NULL, &FR_DBUFF_TMP(nthashhash, NT_DIGEST_LENGTH),
+ &FR_SBUFF_IN(buffer + 8, len), false) != NT_DIGEST_LENGTH) {
REDEBUG("Invalid output from ntlm_auth: NT_KEY has non-hex values");
return -1;
}
len = xlat_eval(charbuf, sizeof(charbuf), request, "%{mschap:LM-Hash %{User-Password}}", NULL, NULL);
if (len < 0) return RLM_MODULE_FAIL;
- if ((fr_hex2bin(&FR_DBUFF_TMP(digest, sizeof(digest)), &FR_SBUFF_IN(charbuf, len)) != (ssize_t)known_good->vp_length) ||
+ if ((fr_hex2bin(NULL, &FR_DBUFF_TMP(digest, sizeof(digest)), &FR_SBUFF_IN(charbuf, len), false) !=
+ (ssize_t)known_good->vp_length) ||
(fr_digest_cmp(digest, known_good->vp_octets, known_good->vp_length) != 0)) {
REDEBUG("LM digest does not match \"known good\" digest");
REDEBUG3("Calculated : %pH", fr_box_octets(digest, sizeof(digest)));
/*
* Sanity check the value of NS-MTA-MD5-Password
*/
- if (fr_hex2bin(&FR_DBUFF_TMP(digest, sizeof(digest)), &FR_SBUFF_IN(known_good->vp_strvalue, known_good->vp_length)) != 16) {
+ if (fr_hex2bin(NULL, &FR_DBUFF_TMP(digest, sizeof(digest)),
+ &FR_SBUFF_IN(known_good->vp_strvalue, known_good->vp_length), false) != 16) {
REDEBUG("\"known good\" NS-MTA-MD5-Password has invalid value");
return RLM_MODULE_INVALID;
}
* Hex data.
*/
len = strlen(data_name + 2);
- if ((len & 0x01) != 0) {
- REDEBUG("Invalid hex string in '%s'", data_name);
- goto nothing;
+ if (len > 0) {
+ fr_sbuff_parse_error_t err;
+
+ input = blob;
+ input_len = fr_hex2bin(&err, &FR_DBUFF_TMP(blob, sizeof(blob)),
+ &FR_SBUFF_IN(data_name + 2, len), true);
+ if (err) {
+ REDEBUG("Invalid hex string in '%s'", data_name);
+ goto nothing;
+ }
}
- input = blob;
- input_len = fr_hex2bin(&FR_DBUFF_TMP(blob, sizeof(blob)), &FR_SBUFF_IN(data_name + 2, len));
-
} else {
GOTO_ERROR;
}