{
size_t length;
- if (a_len > b_len) {
+ if (a_len < b_len) {
length = a_len;
} else {
length = b_len;
switch (*src_type) {
case PW_TYPE_STRING:
{
- char *p;
+ char *p, *buff;
char const *q;
int x;
- dst->strvalue = p = talloc_array(ctx, char, len + 1);
- memcpy(p, src, len);
- p[len] = '\0';
+ buff = p = talloc_bstrndup(ctx, src, len);
/*
* No de-quoting. Just copy the string.
*/
if (!quote) {
ret = len;
+ dst->strvalue = buff;
goto finish;
}
if (quote == '\'') {
q = p;
- while (q < (dst->strvalue + len)) {
+ while (q < (buff + len)) {
/*
* The quotation character is escaped.
*/
}
*p = '\0';
- ret = p - dst->strvalue;
- dst->ptr = talloc_realloc(ctx, dst->ptr, char, ret + 1);
+ ret = p - buff;
+
+ /* Shrink the buffer to the correct size */
+ dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
goto finish;
}
* escaping.
*/
q = p;
- while (q < (dst->strvalue + len)) {
+ while (q < (buff + len)) {
char c = *q++;
- if ((c == '\\') && (q >= (dst->strvalue + len))) {
+ if ((c == '\\') && (q >= (buff + len))) {
fr_strerror_printf("Invalid escape at end of string");
+ talloc_free(buff);
return -1;
}
}
*p = '\0';
- ret = p - dst->strvalue;
- dst->ptr = talloc_realloc(ctx, dst->ptr, char, ret + 1);
+ ret = p - buff;
+ dst->strvalue = talloc_realloc(ctx, buff, char, ret + 1);
}
goto finish;
return -1;
/* raw octets: 0x01020304... */
+#ifndef WITH_ASCEND_BINARY
+ do_octets:
+#endif
case PW_TYPE_OCTETS:
{
uint8_t *p;
goto finish;
}
- do_octets:
len -= 2;
/*
* Invalid.
*/
if ((len & 0x01) != 0) {
- fr_strerror_printf("Length of Hex String is not even, got %zu bytes", ret);
+ fr_strerror_printf("Length of Hex String is not even, got %zu bytes", len);
return -1;
}
case PW_TYPE_ABINARY:
#ifdef WITH_ASCEND_BINARY
- if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) goto do_octets;
+ if ((len > 1) && (strncasecmp(src, "0x", 2) == 0)) {
+ ssize_t bin;
- if (ascend_parse_filter(dst, src, len) < 0 ) {
- /* Allow ascend_parse_filter's strerror to bubble up */
- return -1;
+ if (len > ((sizeof(dst->filter) + 1) * 2)) {
+ fr_strerror_printf("Hex data is too large for ascend filter");
+ return -1;
+ }
+
+ bin = fr_hex2bin((uint8_t *) &dst->filter, ret, src + 2, len - 2);
+ if (bin < ret) {
+ memset(((uint8_t *) &dst->filter) + bin, 0, ret - bin);
+ }
+ } else {
+ if (ascend_parse_filter(dst, src, len) < 0 ) {
+ /* Allow ascend_parse_filter's strerror to bubble up */
+ return -1;
+ }
}
+
ret = sizeof(dst->filter);
goto finish;
#else
dst->integer64 = src->integer;
break;
+ case PW_TYPE_DATE:
+ dst->integer64 = src->date;
+ break;
+
case PW_TYPE_OCTETS:
goto do_octets;
}
/*
+ * We can cast integers less that < INT_MAX to signed
+ */
+ if (dst_type == PW_TYPE_SIGNED) {
+ switch (src_type) {
+ case PW_TYPE_BYTE:
+ dst->sinteger = src->byte;
+ break;
+
+ case PW_TYPE_SHORT:
+ dst->sinteger = src->ushort;
+ break;
+
+ case PW_TYPE_INTEGER:
+ if (src->integer > INT_MAX) {
+ fr_strerror_printf("Invalid cast: From integer to signed. integer value %u is larger "
+ "than max signed int and would overflow", src->integer);
+ return -1;
+ }
+ dst->sinteger = (int)src->integer;
+ break;
+
+ case PW_TYPE_INTEGER64:
+ if (src->integer > INT_MAX) {
+ fr_strerror_printf("Invalid cast: From integer64 to signed. integer64 value %" PRIu64
+ " is larger than max signed int and would overflow", src->integer64);
+ return -1;
+ }
+ dst->sinteger = (int)src->integer64;
+ break;
+
+ case PW_TYPE_OCTETS:
+ goto do_octets;
+
+ default:
+ goto invalid_cast;
+ }
+ goto fixed_length;
+ }
+ /*
* Conversions between IPv4 addresses, IPv6 addresses, IPv4 prefixes and IPv6 prefixes
*
* For prefix to ipaddress conversions, we assume that the host portion has already
#ifdef WITH_ASCEND_BINARY
p = talloc_array(ctx, char, 128);
if (!p) return NULL;
- print_abinary(p, 128, (uint8_t *) &data->filter, inlen, 0);
+ print_abinary(p, 128, (uint8_t const *) &data->filter, inlen, 0);
break;
#else
/* FALL THROUGH */
p[1] = 'x';
fr_bin2hex(p + 2, data->octets, inlen);
+ p[2 + (inlen * 2)] = '\0';
break;
case PW_TYPE_DATE:
DICT_VALUE *v;
char buf[1024]; /* Interim buffer to use with poorly behaved printing functions */
char const *a = NULL;
+ char *p = out;
time_t t;
struct tm s_tm;
unsigned int i;
*out = '\0';
+ p = out;
+
switch (type) {
case PW_TYPE_STRING:
if (quote) {
if (freespace < 3) return inlen + 2;
- *out++ = quote;
+ *p++ = quote;
freespace--;
- len = fr_prints(out, freespace, data->strvalue, inlen, quote);
+ len = fr_prints(p, freespace, data->strvalue, inlen, quote);
/* always terminate the quoted string with another quote */
if (len >= (freespace - 1)) {
+ /* Use out not p as we're operating on the entire buffer */
out[outlen - 2] = (char) quote;
out[outlen - 1] = '\0';
return len + 2;
}
- out += len;
+ p += len;
freespace -= len;
- *out++ = (char) quote;
+ *p++ = (char) quote;
freespace--;
- *out = '\0';
+ *p = '\0';
return len + 2;
}
case PW_TYPE_ABINARY:
#ifdef WITH_ASCEND_BINARY
- print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, len, quote);
+ print_abinary(buf, sizeof(buf), (uint8_t const *) data->filter, inlen, quote);
a = buf;
len = strlen(buf);
break;
case PW_TYPE_OCTETS:
case PW_TYPE_TLV:
{
- size_t max;
+ size_t binlen;
+ size_t hexlen;
- /* Return the number of bytes we would have written */
- len = (inlen * 2) + 2;
- if (freespace <= 1) {
- return len;
- }
+ binlen = inlen;
+ hexlen = (binlen * 2) + 2; /* NOT accounting for trailing NUL */
- *out++ = '0';
- freespace--;
+ /*
+ * If the buffer is too small, put something into
+ * it, and return how much we should have written
+ *
+ * 0 + x + H + H + NUL = 5
+ */
+ if (freespace < 5) {
+ switch (freespace) {
+ case '4':
+ case '3':
+ out[0] = '0';
+ out[1] = 'x';
+ out[2] = '\0';
+ return hexlen;
+
+ case 2:
+ *out = '0';
+ out++;
+ /* FALL-THROUGH */
+
+ case 1:
+ *out = '\0';
+ break;
+
+ case 0:
+ break;
+ }
- if (freespace <= 1) {
- *out = '\0';
- return len;
+ return hexlen;
}
- *out++ = 'x';
- freespace--;
- if (freespace <= 2) {
- *out = '\0';
- return len;
+ /*
+ * The output buffer is at least 5 bytes, we haev
+ * room for '0xHH' plus a trailing NUL byte.
+ */
+ out[0] = '0';
+ out[1] = 'x';
+
+ /*
+ * Get maximum number of bytes we can encode
+ * given freespace, ensuring we account for '0',
+ * 'x', and the trailing NUL in the buffer.
+ *
+ * Note that we can't have "freespace = 0" after
+ * this, as 'freespace' has to be at least 5.
+ */
+ freespace -= 3;
+ freespace /= 2;
+ if (binlen > freespace) {
+ binlen = freespace;
}
- /* Get maximum number of bytes we can encode given freespace */
- max = ((freespace % 2) ? freespace - 1 : freespace - 2) / 2;
- fr_bin2hex(out, data->octets, ((size_t)inlen > max) ? max : (size_t)inlen);
+ fr_bin2hex(out + 2, data->octets, binlen);
+ return hexlen;
}
- return len;
case PW_TYPE_IFID:
a = ifid_ntoa(buf, sizeof(buf), data->ifid);
a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
if (a) {
- char *p = buf;
+ p = buf;
len = strlen(buf);
p += len;
a = inet_ntop(AF_INET, &addr, buf, sizeof(buf));
if (a) {
- char *p = buf;
+ p = buf;
len = strlen(buf);
p += len;