From: Arran Cudbard-Bell Date: Wed, 17 Oct 2012 14:32:41 +0000 (+0100) Subject: fixes #108 Add function to convert FR value pair types to network byte order X-Git-Tag: release_3_0_0_beta1~1660^2~2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=16ab57dda5092953affe4455ed7dda53b23a7e9c;p=thirdparty%2Ffreeradius-server.git fixes #108 Add function to convert FR value pair types to network byte order --- diff --git a/src/include/base64.h b/src/include/base64.h index 84ecf52e98f..645e111906f 100644 --- a/src/include/base64.h +++ b/src/include/base64.h @@ -31,10 +31,10 @@ RCSIDH(base64_h, "$Id$") extern int fr_isbase64 (char ch); -extern void fr_base64_encode (const char *in, size_t inlen, +extern void fr_base64_encode (const uint8_t *in, size_t inlen, char *out, size_t outlen); -extern size_t fr_base64_encode_alloc (const char *in, size_t inlen, char **out); +extern size_t fr_base64_encode_alloc (const uint8_t *in, size_t inlen, char **out); extern int fr_base64_decode (const char *in, size_t inlen, char *out, size_t *outlen); diff --git a/src/include/libradius.h b/src/include/libradius.h index f79d0081c59..487bf739c44 100644 --- a/src/include/libradius.h +++ b/src/include/libradius.h @@ -387,10 +387,12 @@ ssize_t rad_attr2vp_rfc(const RADIUS_PACKET *packet, const uint8_t *data, size_t length, VALUE_PAIR **pvp); -ssize_t rad_attr2vp(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, - const char *secret, - const uint8_t *data, size_t length, - VALUE_PAIR **pvp); +ssize_t rad_attr2vp(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, + const char *secret, + const uint8_t *data, size_t length, + VALUE_PAIR **pvp); + +ssize_t rad_vp2data(const VALUE_PAIR *vp, uint8_t *out, size_t outlen); int rad_vp2extended(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, diff --git a/src/lib/base64.c b/src/lib/base64.c index 2541bf1c05d..b796c6ad480 100644 --- a/src/lib/base64.c +++ b/src/lib/base64.c @@ -63,7 +63,7 @@ to_uchar (char ch) If OUTLEN is less than FR_BASE64_ENC_LENGTH(INLEN), write as many bytes as possible. If OUTLEN is larger than FR_BASE64_ENC_LENGTH(INLEN), also zero terminate the output buffer. */ -void fr_base64_encode (const char *in, size_t inlen, +void fr_base64_encode (const uint8_t *in, size_t inlen, char *out, size_t outlen) { static const char b64str[64] = @@ -71,23 +71,23 @@ void fr_base64_encode (const char *in, size_t inlen, while (inlen && outlen) { - *out++ = b64str[(to_uchar (in[0]) >> 2) & 0x3f]; + *out++ = b64str[(in[0] >> 2) & 0x3f]; if (!--outlen) break; - *out++ = b64str[((to_uchar (in[0]) << 4) - + (--inlen ? to_uchar (in[1]) >> 4 : 0)) + *out++ = b64str[((in[0] << 4) + + (--inlen ? in[1] >> 4 : 0)) & 0x3f]; if (!--outlen) break; *out++ = (inlen - ? b64str[((to_uchar (in[1]) << 2) - + (--inlen ? to_uchar (in[2]) >> 6 : 0)) + ? b64str[((in[1] << 2) + + (--inlen ? in[2] >> 6 : 0)) & 0x3f] : '='); if (!--outlen) break; - *out++ = inlen ? b64str[to_uchar (in[2]) & 0x3f] : '='; + *out++ = inlen ? b64str[in[2] & 0x3f] : '='; if (!--outlen) break; if (inlen) @@ -110,7 +110,7 @@ void fr_base64_encode (const char *in, size_t inlen, indicates length of the requested memory block, i.e., FR_BASE64_ENC_LENGTH(inlen) + 1. */ size_t -fr_base64_encode_alloc (const char *in, size_t inlen, char **out) +fr_base64_encode_alloc (const uint8_t *in, size_t inlen, char **out) { size_t outlen = 1 + FR_BASE64_ENC_LENGTH (inlen); diff --git a/src/lib/radius.c b/src/lib/radius.c index d218213805b..04aaadbe900 100644 --- a/src/lib/radius.c +++ b/src/lib/radius.c @@ -796,7 +796,6 @@ static ssize_t vp2data_tlvs(const RADIUS_PACKET *packet, return ptr - start; } - /** * @brief Encodes the data portion of an attribute. * @return -1 on error, or the length of the data portion. @@ -3844,6 +3843,80 @@ ssize_t rad_attr2vp(const RADIUS_PACKET *packet, return rad_attr2vp_rfc(packet, original, secret, data, length, pvp); } +/** + * @brief Converts vp_data to network byte order + * @return -1 on error, or the length of the value + */ +ssize_t rad_vp2data(const VALUE_PAIR *vp, uint8_t *out, size_t outlen) +{ + size_t len = 0; + uint32_t lvalue; + uint64_t lvalue64; + + len = vp->length; + if (outlen < len) { + fr_strerror_printf("ERROR: rad_vp2data buffer passed too small"); + return -1; + } + + /* + * Short-circuit it for long attributes. + */ + if ((vp->type & PW_FLAG_LONG) != 0) goto do_raw; + + switch(vp->type) { + case PW_TYPE_STRING: + case PW_TYPE_OCTETS: + case PW_TYPE_IFID: + case PW_TYPE_IPADDR: + case PW_TYPE_IPV6ADDR: + case PW_TYPE_IPV6PREFIX: + case PW_TYPE_ABINARY: + case PW_TYPE_TLV: + do_raw: + memcpy(out, vp->vp_octets, len); + break; + case PW_TYPE_BYTE: + out[0] = vp->vp_integer & 0xff; + break; + + case PW_TYPE_SHORT: + out[0] = (vp->vp_integer >> 8) & 0xff; + out[1] = vp->vp_integer & 0xff; + break; + + case PW_TYPE_INTEGER: + lvalue = htonl(vp->vp_integer); + memcpy(out, &lvalue, sizeof(lvalue)); + break; + + case PW_TYPE_INTEGER64: + lvalue64 = htonll(vp->vp_integer64); + memcpy(out, &lvalue64, sizeof(lvalue64)); + break; + + case PW_TYPE_DATE: + lvalue = htonl(vp->vp_date); + memcpy(out, &lvalue, sizeof(lvalue)); + break; + + case PW_TYPE_SIGNED: + { + int32_t slvalue; + + slvalue = htonl(vp->vp_signed); + memcpy(out, &slvalue, sizeof(slvalue)); + break; + } + /* unknown type: ignore it */ + default: + fr_strerror_printf("ERROR: Unknown attribute type %d", + vp->type); + return -1; + } + + return len; +} /** * @brief Calculate/check digest, and decode radius attributes. diff --git a/src/main/xlat.c b/src/main/xlat.c index 22c3eb9f19c..46419fd787b 100644 --- a/src/main/xlat.c +++ b/src/main/xlat.c @@ -525,8 +525,10 @@ static size_t xlat_hex(UNUSED void *instance, REQUEST *request, const char *fmt, char *out, size_t outlen) { size_t i; - uint8_t *p; VALUE_PAIR *vp; + uint8_t buffer[MAX_STRING_LEN]; + ssize_t ret; + size_t len; while (isspace((int) *fmt)) fmt++; @@ -534,21 +536,23 @@ static size_t xlat_hex(UNUSED void *instance, REQUEST *request, *out = '\0'; return 0; } - + + ret = rad_vp2data(vp, buffer, sizeof(buffer)); + len = (size_t) ret; + /* * Don't truncate the data. */ - if (outlen < (vp->length * 2)) { + if ((ret < 0 ) || (outlen < (len * 2))) { *out = 0; return 0; } - p = &vp->vp_octets[0]; - for (i = 0; i < vp->length; i++) { - snprintf(out + 2*i, 3, "%02x", p[i]); + for (i = 0; i < len; i++) { + snprintf(out + 2*i, 3, "%02x", buffer[i]); } - return vp->length * 2; + return len * 2; } /** @@ -558,7 +562,10 @@ static size_t xlat_base64(UNUSED void *instance, REQUEST *request, const char *fmt, char *out, size_t outlen) { VALUE_PAIR *vp; - size_t len; + uint8_t buffer[MAX_STRING_LEN]; + ssize_t ret; + size_t len; + size_t enc; while (isspace((int) *fmt)) fmt++; @@ -567,19 +574,27 @@ static size_t xlat_base64(UNUSED void *instance, REQUEST *request, return 0; } - len = FR_BASE64_ENC_LENGTH(vp->length); + ret = rad_vp2data(vp, buffer, sizeof(buffer)); + if (ret < 0) { + *out = 0; + return 0; + } + + len = (size_t) ret; + + enc = FR_BASE64_ENC_LENGTH(len); /* * Don't truncate the data. */ - if (outlen < (len + 1)) { + if (outlen < (enc + 1)) { *out = 0; return 0; } - fr_base64_encode((char *) vp->vp_octets, vp->length, out, outlen); + fr_base64_encode(buffer, len, out, outlen); - return len; + return enc; } /**