]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Start simplifying the code that encodes attributes
authorAlan T. DeKok <aland@freeradius.org>
Sat, 3 Oct 2009 17:58:17 +0000 (19:58 +0200)
committerAlan T. DeKok <aland@freeradius.org>
Tue, 20 Oct 2009 22:29:49 +0000 (00:29 +0200)
src/lib/radius.c

index 3386d26a51f477b1764d99d9690dc2ef8a05806a..326ed52172373180dc1e8bef969a8ae4bf075d43 100644 (file)
@@ -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.
         */