From 326a68b90a1a5c78aa6130fc695a34ae08d6d197 Mon Sep 17 00:00:00 2001 From: "Alan T. DeKok" Date: Sat, 3 Oct 2009 19:58:17 +0200 Subject: [PATCH] Start simplifying the code that encodes attributes --- src/lib/radius.c | 176 +++++++++++++++++++++++++++++++---------------- 1 file changed, 116 insertions(+), 60 deletions(-) diff --git a/src/lib/radius.c b/src/lib/radius.c index c2aea3d7af4..9ef943d3df9 100644 --- a/src/lib/radius.c +++ b/src/lib/radius.c @@ -140,6 +140,68 @@ void fr_printf_log(const char *fmt, ...) return; } +static void print_hex(RADIUS_PACKET *packet) +{ + int i; + + if (!packet->data) return; + + printf(" Code:\t\t%u\n", packet->data[0]); + printf(" Id:\t\t%u\n", packet->data[1]); + printf(" Length:\t%u\n", ((packet->data[2] << 8) | + (packet->data[3]))); + printf(" Vector:\t"); + for (i = 4; i < 20; i++) { + printf("%02x", packet->data[i]); + } + printf("\n"); + + if (packet->data_len > 20) { + int total; + const uint8_t *ptr; + printf(" Data:"); + + total = packet->data_len - 20; + ptr = packet->data + 20; + + while (total > 0) { + int attrlen; + + printf("\t\t"); + if (total < 2) { /* too short */ + printf("%02x\n", *ptr); + break; + } + + if (ptr[1] > total) { /* too long */ + for (i = 0; i < total; i++) { + printf("%02x ", ptr[i]); + } + break; + } + + printf("%02x %02x ", ptr[0], ptr[1]); + attrlen = ptr[1] - 2; + ptr += 2; + total -= 2; + + for (i = 0; i < attrlen; i++) { + if ((i > 0) && ((i & 0x0f) == 0x00)) + printf("\t\t\t"); + printf("%02x ", ptr[i]); + if ((i & 0x0f) == 0x0f) printf("\n"); + } + + if ((attrlen & 0x0f) != 0x00) printf("\n"); + + ptr += attrlen; + total -= attrlen; + } + } + fflush(stdout); +} + + /* * Wrapper for sendto which handles sendfromto, IPv6, and all * possible combinations. @@ -571,9 +633,13 @@ static void make_tunnel_passwd(uint8_t *output, size_t *outlen, memcpy(output, passwd, len + 2); } -static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, - const char *secret, const VALUE_PAIR *vp, uint8_t *ptr, - size_t offset, size_t room) +/* + * Returns the end of the data. + */ +static uint8_t *vp2data(const RADIUS_PACKET *packet, + const RADIUS_PACKET *original, + const char *secret, const VALUE_PAIR *vp, uint8_t *ptr, + size_t room) { uint32_t lvalue; size_t len; @@ -600,7 +666,6 @@ static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, len = 1; /* just in case */ array[0] = vp->vp_integer & 0xff; data = array; - offset = 0; break; case PW_TYPE_SHORT: @@ -608,19 +673,13 @@ static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, array[0] = (vp->vp_integer >> 8) & 0xff; array[1] = vp->vp_integer & 0xff; data = array; - offset = 0; break; case PW_TYPE_INTEGER: len = 4; /* just in case */ lvalue = htonl(vp->vp_integer); memcpy(array, &lvalue, sizeof(lvalue)); - - /* - * Perhaps discard the first octet. - */ - data = &array[offset]; - len -= offset; + data = array; break; case PW_TYPE_IPADDR: @@ -651,21 +710,19 @@ static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, data = vp->vp_tlv; if (!data) { fr_strerror_printf("ERROR: Cannot encode NULL TLV"); - return -1; + return NULL; } break; default: /* unknown type: ignore it */ fr_strerror_printf("ERROR: Unknown attribute type %d", vp->type); - return -1; + return NULL; } /* - * Bound the data to 255 bytes. + * Bound the data to the calling size */ - if (len + offset > room) { - len = room - offset; - } + if (len > room) len = room; /* * Encrypt the various password styles @@ -675,22 +732,19 @@ static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, */ switch (vp->flags.encrypt) { case FLAG_ENCRYPT_USER_PASSWORD: - make_passwd(ptr + offset, &len, - data, len, + make_passwd(ptr, &len, data, len, secret, packet->vector); break; case FLAG_ENCRYPT_TUNNEL_PASSWORD: /* - * Check if 255 - offset - total_length is less - * than 18. If so, we can't fit the data into - * the available space, and we discard the - * attribute. + * Check if there's enough room. If there isn't, + * we discard the attribute. * * This is ONLY a problem if we have multiple VSA's * in one Vendor-Specific, though. */ - if ((room - offset) < 18) return 0; + if (room < 18) return ptr; switch (packet->code) { case PW_AUTHENTICATION_ACK: @@ -699,17 +753,15 @@ static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, default: if (!original) { fr_strerror_printf("ERROR: No request packet, cannot encrypt %s attribute in the vp.", vp->name); - return -1; + return NULL; } - make_tunnel_passwd(ptr + offset, &len, - data, len, room - offset, + make_tunnel_passwd(ptr, &len, data, len, room, secret, original->vector); break; case PW_ACCOUNTING_REQUEST: case PW_DISCONNECT_REQUEST: case PW_COA_REQUEST: - make_tunnel_passwd(ptr + offset, &len, - data, len, room - offset, + make_tunnel_passwd(ptr, &len, data, len, room, secret, packet->vector); break; } @@ -720,8 +772,7 @@ static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, * always fits. */ case FLAG_ENCRYPT_ASCEND_SECRET: - make_secret(ptr + offset, packet->vector, - secret, data); + make_secret(ptr, packet->vector, secret, data); len = AUTH_VECTOR_LEN; break; @@ -730,11 +781,11 @@ static int vp2data(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, /* * Just copy the data over */ - memcpy(ptr + offset, data, len); + memcpy(ptr, data, len); break; } /* switch over encryption flags */ - return len; + return ptr + len; } @@ -743,7 +794,7 @@ static VALUE_PAIR *rad_vp2tlv(VALUE_PAIR *vps) int maxattr = 0; int length; unsigned int attribute; - uint8_t *ptr; + uint8_t *ptr, *end; VALUE_PAIR *vp, *tlv; attribute = vps->attribute & 0xffff00ff; @@ -793,13 +844,15 @@ static VALUE_PAIR *rad_vp2tlv(VALUE_PAIR *vps) } maxattr = vp->attribute & 0xff00; - length = vp2data(NULL, NULL, NULL, vp, ptr + 2, 0, - tlv->vp_tlv + tlv->length - ptr); - if (length < 0) { + end = vp2data(NULL, NULL, NULL, vp, ptr + 2, + tlv->vp_tlv + tlv->length - ptr); + if (!end) { vp->length = ptr - vp->vp_tlv; return tlv; /* should be a more serious error... */ } + length = (end - ptr); + /* * Pack the attribute. */ @@ -895,11 +948,13 @@ int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, const char *secret, const VALUE_PAIR *vp, uint8_t *start) { int vendorcode; - int offset, len, total_length; + int len, total_length; uint32_t lvalue; uint8_t *ptr, *length_ptr, *vsa_length_ptr, *tlv_length_ptr; + uint8_t *end; ptr = start; + end = ptr + 255; vendorcode = total_length = 0; length_ptr = vsa_length_ptr = tlv_length_ptr = NULL; @@ -1017,30 +1072,29 @@ int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, *length_ptr += vsa_tlen + vsa_llen + vsa_offset; } - offset = 0; - if (vp->flags.has_tag) { - if (TAG_VALID(vp->flags.tag)) { - ptr[0] = vp->flags.tag & 0xff; - offset = 1; - - } else if (vp->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) { - /* - * Tunnel passwords REQUIRE a tag, even - * if don't have a valid tag. - */ - ptr[0] = 0; - offset = 1; - } /* else don't write a tag */ - } /* else the attribute doesn't have a tag */ - - len = vp2data(packet, original, secret, vp, ptr, offset, - 255 - total_length); - if (len < 0) return -1; + /* + * Insert tags for string attributes. They go BEFORE + * the string. + */ + if (vp->flags.has_tag && (vp->type == PW_TYPE_STRING) && + (TAG_VALID(vp->flags.tag) || + (vp->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD))) { + ptr[0] = vp->flags.tag; + end = vp2data(packet, original, secret, vp, ptr + 1, + (end - ptr) - 1); + } else { + end = vp2data(packet, original, secret, vp, ptr, + (end - ptr)); + } + if (!end) return -1; /* - * Account for the tag (if any). + * Insert tags for integer attributes. They go at the START + * of the integer, and over-write the first byte. */ - len += offset; + if (vp->flags.has_tag && (vp->type == PW_TYPE_INTEGER)) { + ptr[0] = vp->flags.tag; + } /* * RFC 2865 section 5 says that zero-length attributes @@ -1050,9 +1104,11 @@ int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original, * one vendor. Don't they have anything better to do * with their time? */ - if ((len == 0) && + if ((end == ptr) && (vp->attribute != PW_CHARGEABLE_USER_IDENTITY)) return 0; + len = (end - ptr); + /* * Update the various lengths. */ -- 2.47.3