Merge branch 'sam'
[freeradius.git] / src / lib / radius.c
index 5ea11cf..8bcca4f 100644 (file)
@@ -1,5 +1,6 @@
-/*
- * radius.c    Functions to send/receive radius packets.
+/**
+ * @file radius.c
+ * @brief Functions to send/receive radius packets.
  *
  * Version:    $Id$
  *
@@ -147,59 +148,81 @@ void fr_printf_log(const char *fmt, ...)
        return;
 }
 
+static const char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
+
+static void print_hex_data(const uint8_t *ptr, int attrlen, int depth)
+{
+       int i;
+
+       for (i = 0; i < attrlen; i++) {
+               if ((i > 0) && ((i & 0x0f) == 0x00))
+                       fprintf(fr_log_fp, "%.*s", depth, tabs);
+               fprintf(fr_log_fp, "%02x ", ptr[i]);
+               if ((i & 0x0f) == 0x0f) fprintf(fr_log_fp, "\n");
+       }
+       if ((i & 0x0f) != 0) fprintf(fr_log_fp, "\n");
+}
+
+
 void rad_print_hex(RADIUS_PACKET *packet)
 {
        int i;
 
-       if (!packet->data) return;
+       if (!packet->data || !fr_log_fp) 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) |
+       fprintf(fr_log_fp, "  Code:\t\t%u\n", packet->data[0]);
+       fprintf(fr_log_fp, "  Id:\t\t%u\n", packet->data[1]);
+       fprintf(fr_log_fp, "  Length:\t%u\n", ((packet->data[2] << 8) |
                                   (packet->data[3])));
-       printf("  Vector:\t");
+       fprintf(fr_log_fp, "  Vector:\t");
        for (i = 4; i < 20; i++) {
-               printf("%02x", packet->data[i]);
+               fprintf(fr_log_fp, "%02x", packet->data[i]);
        }
-       printf("\n");
+       fprintf(fr_log_fp, "\n");
 
        if (packet->data_len > 20) {
                int total;
                const uint8_t *ptr;
-               printf("  Data:");
+               fprintf(fr_log_fp, "  Data:");
 
                total = packet->data_len - 20;
                ptr = packet->data + 20;
 
                while (total > 0) {
                        int attrlen;
+                       unsigned int vendor = 0;
 
-                       printf("\t\t");
+                       fprintf(fr_log_fp, "\t\t");
                        if (total < 2) { /* too short */
-                               printf("%02x\n", *ptr);
+                               fprintf(fr_log_fp, "%02x\n", *ptr);
                                break;
                        }
 
                        if (ptr[1] > total) { /* too long */
                                for (i = 0; i < total; i++) {
-                                       printf("%02x ", ptr[i]);
+                                       fprintf(fr_log_fp, "%02x ", ptr[i]);
                                }
                                break;
                        }
 
-                       printf("%02x  %02x  ", ptr[0], ptr[1]);
+                       fprintf(fr_log_fp, "%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 ((ptr[0] == PW_VENDOR_SPECIFIC) &&
+                           (attrlen > 4)) {
+                               vendor = (ptr[3] << 16) | (ptr[4] << 8) | ptr[5];
+                               fprintf(fr_log_fp, "%02x%02x%02x%02x (%u)  ",
+                                      ptr[2], ptr[3], ptr[4], ptr[5], vendor);
+                               attrlen -= 4;
+                               ptr += 6;
+                               total -= 6;
+
+                       } else {
+                               ptr += 2;
+                               total -= 2;
                        }
 
-                       if ((attrlen & 0x0f) != 0x00) printf("\n");
+                       print_hex_data(ptr, attrlen, 3);
 
                        ptr += attrlen;
                        total -= attrlen;
@@ -208,8 +231,8 @@ void rad_print_hex(RADIUS_PACKET *packet)
        fflush(stdout);
 }
 
-/*
- *     Wrapper for sendto which handles sendfromto, IPv6, and all
+/**
+ * @brief Wrapper for sendto which handles sendfromto, IPv6, and all
  *     possible combinations.
  */
 static int rad_sendto(int sockfd, void *data, size_t data_len, int flags,
@@ -255,6 +278,9 @@ static int rad_sendto(int sockfd, void *data, size_t data_len, int flags,
         */
        rcode = sendto(sockfd, data, data_len, flags,
                       (struct sockaddr *) &dst, sizeof_dst);
+#ifdef WITH_UDPFROMTO
+done:
+#endif
        if (rcode < 0) {
                DEBUG("rad_send() failed: %s\n", strerror(errno));
        }
@@ -342,8 +368,8 @@ ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, int *src_port,
 }
 
 
-/*
- *     wrapper for recvfrom, which handles recvfromto, IPv6, and all
+/**
+ * @brief wrapper for recvfrom, which handles recvfromto, IPv6, and all
  *     possible combinations.
  */
 static ssize_t rad_recvfrom(int sockfd, uint8_t **pbuf, int flags,
@@ -470,17 +496,15 @@ static ssize_t rad_recvfrom(int sockfd, uint8_t **pbuf, int flags,
 
 
 #define AUTH_PASS_LEN (AUTH_VECTOR_LEN)
-/*************************************************************************
- *
- *      Function: make_secret
- *
- *      Purpose: Build an encrypted secret value to return in a reply
- *               packet.  The secret is hidden by xoring with a MD5 digest
+/**
+ * @brief Build an encrypted secret value to return in a reply packet
+ * 
+ *               The secret is hidden by xoring with a MD5 digest
  *               created from the shared secret and the authentication
  *               vector.  We put them into MD5 in the reverse order from
  *               that used when encrypting passwords to RADIUS.
  *
- *************************************************************************/
+ */
 static void make_secret(uint8_t *digest, const uint8_t *vector,
                        const char *secret, const uint8_t *value)
 {
@@ -650,7 +674,7 @@ extern int fr_attr_max_tlv;
 extern int fr_attr_shift[];
 extern int fr_attr_mask[];
 
-static int do_next_tlv(const VALUE_PAIR *vp, int nest)
+static int do_next_tlv(const VALUE_PAIR *vp, const VALUE_PAIR *next, int nest)
 {
        unsigned int tlv1, tlv2;
 
@@ -669,18 +693,18 @@ static int do_next_tlv(const VALUE_PAIR *vp, int nest)
        /*
         *      Nothing to follow, we're done.
         */
-       if (!vp->next) return 0;
+       if (!next) return 0;
 
        /*
         *      Not from the same vendor, skip it.
         */
-       if (vp->vendor != vp->next->vendor) return 0;
+       if (vp->vendor != next->vendor) return 0;
 
        /*
         *      In a different TLV space, skip it.
         */
        tlv1 = vp->attribute;
-       tlv2 = vp->next->attribute;
+       tlv2 = next->attribute;
        
        tlv1 &= ((1 << fr_attr_shift[nest]) - 1);
        tlv2 &= ((1 << fr_attr_shift[nest]) - 1);
@@ -702,8 +726,8 @@ static ssize_t vp2attr_rfc(const RADIUS_PACKET *packet,
                           const char *secret, const VALUE_PAIR **pvp,
                           unsigned int attribute, uint8_t *ptr, size_t room);
 
-/*
- *     This is really a sub-function of vp2data_any.  It encodes
+/**
+ * @brief This is really a sub-function of vp2data_any().  It encodes
  *     the *data* portion of the TLV, and assumes that the encapsulating
  *     attribute has already been encoded.
  */
@@ -716,8 +740,10 @@ static ssize_t vp2data_tlvs(const RADIUS_PACKET *packet,
        ssize_t len;
        size_t my_room;
        uint8_t *ptr = start;
-       const VALUE_PAIR *old_vp;
        const VALUE_PAIR *vp = *pvp;
+       const VALUE_PAIR *svp = vp;
+
+       if (!svp) return 0;
 
 #ifndef NDEBUG
        if (nest > fr_attr_max_tlv) {
@@ -729,12 +755,9 @@ static ssize_t vp2data_tlvs(const RADIUS_PACKET *packet,
        while (vp) {
                if (room < 2) return ptr - start;
                
-               old_vp = vp;
                ptr[0] = (vp->attribute >> fr_attr_shift[nest]) & fr_attr_mask[nest];
                ptr[1] = 2;
                
-               VP_TRACE("TLV encoded %s %u\n", vp->name, start[0]);
-               
                my_room = room;
                if (room > 255) my_room = 255;
 
@@ -743,22 +766,39 @@ static ssize_t vp2data_tlvs(const RADIUS_PACKET *packet,
                if (len < 0) return len;
                if (len == 0) return ptr - start;
                /* len can NEVER be more than 253 */
-               
+
                ptr[1] += len;
+
+#ifndef NDEBUG
+               if ((fr_debug_flag > 3) && fr_log_fp) {
+                       fprintf(fr_log_fp, "\t\t%02x %02x  ", ptr[0], ptr[1]);
+                       print_hex_data(ptr + 2, len, 3);
+               }
+#endif
+
                room -= ptr[1];
                ptr += ptr[1];
                *pvp = vp;
                
-               if (!do_next_tlv(old_vp, nest)) break;
+               if (!do_next_tlv(svp, vp, nest)) break;
        }
 
+#ifndef NDEBUG
+       if ((fr_debug_flag > 3) && fr_log_fp) {
+               DICT_ATTR *da;
+               
+               da = dict_attrbyvalue(svp->attribute & ((1 << fr_attr_shift[nest ]) - 1), svp->vendor);
+               if (da) fprintf(fr_log_fp, "\t%s = ...\n", da->name);
+       }
+#endif
+
        return ptr - start;
 }
 
 
-/*
- *     Encodes the data portion of an attribute.
- *     Returns -1 on error, or the length of the data portion.
+/**
+ * @brief Encodes the data portion of an attribute.
+ * @return -1 on error, or the length of the data portion.
  */
 static ssize_t vp2data_any(const RADIUS_PACKET *packet,
                           const RADIUS_PACKET *original,
@@ -771,6 +811,7 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
        const uint8_t *data;
        uint8_t *ptr = start;
        uint8_t array[4];
+       uint64_t lvalue64;
        const VALUE_PAIR *vp = *pvp;
 
        /*
@@ -781,14 +822,13 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
         *
         *      If we cared about the stack, we could unroll the loop.
         */
-       VP_TRACE("vp2data_any: %u attr %u -> %u\n",
-                nest, vp->attribute, vp->attribute >> fr_attr_shift[nest + 1]);
        if (vp->flags.is_tlv && (nest < fr_attr_max_tlv) &&
            ((vp->attribute >> fr_attr_shift[nest + 1]) != 0)) {
                return vp2data_tlvs(packet, original, secret, nest + 1, pvp,
                                    start, room);
        }
-       VP_TRACE("vp2data_any: Encoding %s\n", vp->name);
+
+       debug_pair(vp);
 
        /*
         *      Set up the default sources for the data.
@@ -796,6 +836,12 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
        data = vp->vp_octets;
        len = vp->length;
 
+       /*
+        *      Short-circuit it for long attributes.  They can't be
+        *      encrypted, tagged, etc.
+        */
+       if ((vp->type & PW_FLAG_LONG) != 0) goto do_tlv;
+
        switch(vp->type) {
        case PW_TYPE_STRING:
        case PW_TYPE_OCTETS:
@@ -826,6 +872,12 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
                data = array;
                break;
 
+       case PW_TYPE_INTEGER64:
+               len = 8;        /* just in case */
+               lvalue64 = htonll(vp->vp_integer64);
+               data = (uint8_t *) &lvalue64;
+               break;
+
        case PW_TYPE_IPADDR:
                data = (const uint8_t *) &vp->vp_ipaddr;
                len = 4;        /* just in case */
@@ -851,12 +903,12 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
        }
 
        case PW_TYPE_TLV:
+       do_tlv:
                data = vp->vp_tlv;
                if (!data) {
                        fr_strerror_printf("ERROR: Cannot encode NULL TLV");
                        return -1;
                }
-               len = vp->length;
                break;
 
        default:                /* unknown type: ignore it */
@@ -865,6 +917,14 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
        }
 
        /*
+        *      No data: skip it.
+        */
+       if (len == 0) {
+               *pvp = vp->next;
+               return 0;
+       }
+
+       /*
         *      Bound the data to the calling size
         */
        if (len > (ssize_t) room) len = room;
@@ -944,7 +1004,7 @@ static ssize_t vp2data_any(const RADIUS_PACKET *packet,
        } /* switch over encryption flags */
 
        *pvp = vp->next;
-       return len + (ptr - start);;
+       return len + (ptr - start);
 }
 
 static ssize_t attr_shift(const uint8_t *start, const uint8_t *end,
@@ -1007,8 +1067,8 @@ static ssize_t attr_shift(const uint8_t *start, const uint8_t *end,
 }
 
 
-/*
- *     Encode an "extended" attribute.
+/**
+ * @brief Encode an "extended" attribute.
  */
 int rad_vp2extended(const RADIUS_PACKET *packet,
                    const RADIUS_PACKET *original,
@@ -1021,7 +1081,6 @@ int rad_vp2extended(const RADIUS_PACKET *packet,
        uint8_t *start = ptr;
        const VALUE_PAIR *vp = *pvp;
 
-       VP_TRACE("rad_vp2extended %s\n", vp->name);
        if (vp->vendor < VENDORPEC_EXTENDED) {
                fr_strerror_printf("rad_vp2extended called for non-extended attribute");
                return -1;
@@ -1081,7 +1140,7 @@ int rad_vp2extended(const RADIUS_PACKET *packet,
 
        len = vp2data_any(packet, original, secret, nest,
                          pvp, ptr + ptr[1], room - hdr_len);
-       if (len < 0) return len;
+       if (len <= 0) return len;
 
        /*
         *      There may be more than 252 octets of data encoded in
@@ -1095,12 +1154,40 @@ int rad_vp2extended(const RADIUS_PACKET *packet,
 
        ptr[1] += len;
        
+#ifndef NDEBUG
+       if ((fr_debug_flag > 3) && fr_log_fp) {
+               int jump = 3;
+
+               fprintf(fr_log_fp, "\t\t%02x %02x  ", ptr[0], ptr[1]);
+               if (!vp->flags.extended_flags) {
+                       fprintf(fr_log_fp, "%02x  ", ptr[2]);
+                       
+               } else {
+                       fprintf(fr_log_fp, "%02x %02x  ", ptr[2], ptr[3]);
+                       jump = 4;
+               }
+
+               if (vp->flags.evs) {
+                       fprintf(fr_log_fp, "%02x%02x%02x%02x (%u)  %02x  ",
+                               ptr[jump], ptr[jump + 1],
+                               ptr[jump + 2], ptr[jump + 3],
+                               ((ptr[jump + 1] << 16) |
+                                (ptr[jump + 2] << 8) |
+                                ptr[jump + 3]),
+                               ptr[jump + 4]);
+                       jump += 5;
+               }
+
+               print_hex_data(ptr + jump, len, 3);
+       }
+#endif
+
        return (ptr + ptr[1]) - start;
 }
 
 
-/*
- *     Encode a WiMAX attribute.
+/**
+ * @brief Encode a WiMAX attribute.
  */
 int rad_vp2wimax(const RADIUS_PACKET *packet,
                 const RADIUS_PACKET *original,
@@ -1158,11 +1245,24 @@ int rad_vp2wimax(const RADIUS_PACKET *packet,
        ptr[1] += len;
        ptr[7] += len;
 
+#ifndef NDEBUG
+       if ((fr_debug_flag > 3) && fr_log_fp) {
+               fprintf(fr_log_fp, "\t\t%02x %02x  %02x%02x%02x%02x (%u)  %02x %02x %02x   ",
+                      ptr[0], ptr[1],
+                      ptr[2], ptr[3], ptr[4], ptr[5],
+                      (ptr[3] << 16) | (ptr[4] << 8) | ptr[5],
+                      ptr[6], ptr[7], ptr[8]);
+               print_hex_data(ptr + 9, len, 3);
+       }
+#endif
+
        return (ptr + ptr[1]) - start;
 }
 
-/*
- *     Encode an RFC format TLV.  This could be a standard attribute,
+/**
+ * @brief Encode an RFC format TLV.
+ *
+ *     This could be a standard attribute,
  *     or a TLV data type.  If it's a standard attribute, then
  *     vp->attribute == attribute.  Otherwise, attribute may be
  *     something else.
@@ -1182,16 +1282,23 @@ static ssize_t vp2attr_rfc(const RADIUS_PACKET *packet,
        if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
 
        len = vp2data_any(packet, original, secret, 0, pvp, ptr + ptr[1], room);
-       if (len < 0) return len;
+       if (len <= 0) return len;
 
        ptr[1] += len;
 
+#ifndef NDEBUG
+       if ((fr_debug_flag > 3) && fr_log_fp) {
+               fprintf(fr_log_fp, "\t\t%02x %02x  ", ptr[0], ptr[1]);
+               print_hex_data(ptr + 2, len, 3);
+       }
+#endif
+
        return ptr[1];
 }
 
 
-/*
- *     Encode a VSA which is a TLV.  If it's in the RFC format, call
+/**
+ * @brief Encode a VSA which is a TLV.  If it's in the RFC format, call
  *     vp2attr_rfc.  Otherwise, encode it here.
  */
 static ssize_t vp2attr_vsa(const RADIUS_PACKET *packet,
@@ -1208,12 +1315,9 @@ static ssize_t vp2attr_vsa(const RADIUS_PACKET *packet,
         *      Unknown vendor: RFC format.
         *      Known vendor and RFC format: go do that.
         */
-       VP_TRACE("Encoding VSA %u.%u\n", vendor, attribute);
        dv = dict_vendorbyvalue(vendor);
-       VP_TRACE("Flags %d %d\n", vp->flags.is_tlv, vp->flags.has_tlv);
        if (!dv ||
            (!vp->flags.is_tlv && (dv->type == 1) && (dv->length == 1))) {
-               VP_TRACE("Encoding RFC %u.%u\n", vendor, attribute);
                return vp2attr_rfc(packet, original, secret, pvp,
                                   attribute, ptr, room);
        }
@@ -1252,10 +1356,11 @@ static ssize_t vp2attr_vsa(const RADIUS_PACKET *packet,
 
        case 2:
                ptr[dv->type] = 0;
-               /* FALL-THROUGH */
+               ptr[dv->type + 1] = dv->type + 2;
+               break;
 
        case 1:
-               ptr[dv->type + dv->length - 1] = dv->type + dv->length;
+               ptr[dv->type] = dv->type + 1;
                break;
 
        }
@@ -1266,16 +1371,63 @@ static ssize_t vp2attr_vsa(const RADIUS_PACKET *packet,
 
        len = vp2data_any(packet, original, secret, 0, pvp,
                          ptr + dv->type + dv->length, room);
-       if (len < 0) return len;
+       if (len <= 0) return len;
 
        if (dv->length) ptr[dv->type + dv->length - 1] += len;
 
+#ifndef NDEBUG
+       if ((fr_debug_flag > 3) && fr_log_fp) {
+               switch (dv->type) {
+               default:
+                       break;
+
+               case 4:
+                       if ((fr_debug_flag > 3) && fr_log_fp)
+                               fprintf(fr_log_fp, "\t\t%02x%02x%02x%02x ",
+                                       ptr[0], ptr[1], ptr[2], ptr[3]);
+                       break;
+                       
+               case 2:
+                       if ((fr_debug_flag > 3) && fr_log_fp)
+                               fprintf(fr_log_fp, "\t\t%02x%02x ",
+                                       ptr[0], ptr[1]);
+               break;
+               
+               case 1:
+                       if ((fr_debug_flag > 3) && fr_log_fp)
+                               fprintf(fr_log_fp, "\t\t%02x ", ptr[0]);
+                       break;
+               }
+               
+               switch (dv->length) {
+               default:
+                       break;
+
+               case 0:
+                       fprintf(fr_log_fp, "  ");
+                       break;
+
+               case 1:
+                       fprintf(fr_log_fp, "%02x  ",
+                               ptr[dv->type]);
+                       break;
+
+               case 2:
+                       fprintf(fr_log_fp, "%02x%02x  ",
+                               ptr[dv->type], ptr[dv->type] + 1);
+                       break;
+               }
+
+               print_hex_data(ptr + dv->type + dv->length, len, 3);
+       }
+#endif
+
        return dv->type + dv->length + len;
 }
 
 
-/*
- *     Encode a Vendor-Specific attribute.
+/**
+ * @brief Encode a Vendor-Specific attribute.
  */
 int rad_vp2vsa(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                const char *secret, const VALUE_PAIR **pvp, uint8_t *ptr,
@@ -1319,14 +1471,24 @@ int rad_vp2vsa(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                          ptr + ptr[1], room);
        if (len < 0) return len;
 
+#ifndef NDEBUG
+       if ((fr_debug_flag > 3) && fr_log_fp) {
+               fprintf(fr_log_fp, "\t\t%02x %02x  %02x%02x%02x%02x (%u)  ",
+                      ptr[0], ptr[1],
+                      ptr[2], ptr[3], ptr[4], ptr[5],
+                      (ptr[3] << 16) | (ptr[4] << 8) | ptr[5]);
+               print_hex_data(ptr + 6, len, 3);
+       }
+#endif
+
        ptr[1] += len;
 
        return ptr[1];
 }
 
 
-/*
- *     Encode an RFC standard attribute 1..255
+/**
+ * @brief Encode an RFC standard attribute 1..255
  */
 int rad_vp2rfc(const RADIUS_PACKET *packet,
               const RADIUS_PACKET *original,
@@ -1345,9 +1507,17 @@ int rad_vp2rfc(const RADIUS_PACKET *packet,
                return -1;
        }
 
+       /*
+        *      Only CUI is allowed to have zero length.
+        *      Thank you, WiMAX!
+        */
        if ((vp->length == 0) &&
-           (vp->attribute != PW_CHARGEABLE_USER_IDENTITY)) {
-               return 0;
+           (vp->attribute == PW_CHARGEABLE_USER_IDENTITY)) {
+               ptr[0] = PW_CHARGEABLE_USER_IDENTITY;
+               ptr[1] = 2;
+
+               *pvp = vp->next;
+               return 2;
        }
 
        return vp2attr_rfc(packet, original, secret, pvp, vp->attribute,
@@ -1355,8 +1525,8 @@ int rad_vp2rfc(const RADIUS_PACKET *packet,
 }
 
 
-/*
- *     Parse a data structure into a RADIUS attribute.
+/**
+ * @brief Parse a data structure into a RADIUS attribute.
  */
 int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                const char *secret, const VALUE_PAIR **pvp, uint8_t *start,
@@ -1380,9 +1550,16 @@ int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                if (vp->attribute == PW_MESSAGE_AUTHENTICATOR) {
                        if (room < 18) return -1;
                        
+                       debug_pair(vp);
                        start[0] = PW_MESSAGE_AUTHENTICATOR;
                        start[1] = 18;
                        memset(start + 2, 0, 16);
+#ifndef NDEBUG
+                       if ((fr_debug_flag > 3) && fr_log_fp) {
+                               fprintf(fr_log_fp, "\t\t50 12 ...\n");
+                       }
+#endif
+
                        *pvp = (*pvp)->next;
                        return 18;
                }
@@ -1406,8 +1583,8 @@ int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
 }
 
 
-/*
- *     Encode a packet.
+/**
+ * @brief Encode a packet.
  */
 int rad_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
               const char *secret)
@@ -1500,6 +1677,9 @@ int rad_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
         */
        reply = packet->vps;
        while (reply) {
+               size_t last_len;
+               const char *last_name = NULL;
+
                /*
                 *      Ignore non-wire attributes, but allow extended
                 *      attributes.
@@ -1533,14 +1713,11 @@ int rad_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                         *      Message-Authenticator
                         */
                        packet->offset = total_length;
+                       last_len = 16;
+               } else {
+                       last_len = reply->length;
                }
-
-               /*
-                *      Print out ONLY the attributes which
-                *      we're sending over the wire, and print
-                *      them out BEFORE they're encrypted.
-                */
-               debug_pair(reply);
+               last_name = reply->name;
 
                len = rad_vp2attr(packet, original, secret, &reply, ptr,
                                  ((uint8_t *) data) + sizeof(data) - ptr);
@@ -1550,10 +1727,12 @@ int rad_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                 *      Failed to encode the attribute, likely because
                 *      the packet is full.
                 */
-               if ((len == 0) &&
-                   (total_length > (sizeof(data) - 2 - reply->length))) {
-                       DEBUG("WARNING: Attributes are too long for packet.  Discarding data past %d bytes", total_length);
-                       break;
+               if (len == 0) {
+                       if (last_len != 0) {
+                               DEBUG("WARNING: Failed encoding attribute %s\n", last_name);
+                       } else {
+                               DEBUG("WARNING: Skipping zero-length attribute %s\n", last_name);
+                       }
                }
 
 #ifndef NDEBUG
@@ -1588,8 +1767,8 @@ int rad_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
 }
 
 
-/*
- *     Sign a previously encoded packet.
+/**
+ * @brief Sign a previously encoded packet.
  */
 int rad_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
             const char *secret)
@@ -1618,8 +1797,12 @@ int rad_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                uint8_t calc_auth_vector[AUTH_VECTOR_LEN];
 
                switch (packet->code) {
-               case PW_ACCOUNTING_REQUEST:
                case PW_ACCOUNTING_RESPONSE:
+                       if (original && original->code == PW_STATUS_SERVER) {
+                               goto do_ack;
+                       }
+
+               case PW_ACCOUNTING_REQUEST:
                case PW_DISCONNECT_REQUEST:
                case PW_DISCONNECT_ACK:
                case PW_DISCONNECT_NAK:
@@ -1629,6 +1812,7 @@ int rad_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                        memset(hdr->vector, 0, AUTH_VECTOR_LEN);
                        break;
 
+               do_ack:
                case PW_AUTHENTICATION_ACK:
                case PW_AUTHENTICATION_REJECT:
                case PW_ACCESS_CHALLENGE:
@@ -1701,8 +1885,8 @@ int rad_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
        return 0;
 }
 
-/*
- *     Reply to the request.  Also attach
+/**
+ * @brief Reply to the request.  Also attach
  *     reply attribute value pairs and any user message provided.
  */
 int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
@@ -1763,7 +1947,7 @@ int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
        }
 
 #ifndef NDEBUG
-       if (fr_debug_flag > 3) rad_print_hex(packet);
+       if ((fr_debug_flag > 3) && fr_log_fp) rad_print_hex(packet);
 #endif
 
        /*
@@ -1774,9 +1958,11 @@ int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original,
                          &packet->dst_ipaddr, packet->dst_port);
 }
 
-/*
- *     Do a comparison of two authentication digests by comparing
- *     the FULL digest.  Otehrwise, the server can be subject to
+/**
+ * @brief Do a comparison of two authentication digests by comparing
+ *     the FULL digest.
+ *
+ *     Otherwise, the server can be subject to
  *     timing attacks that allow attackers find a valid message
  *     authenticator.
  *
@@ -1795,8 +1981,8 @@ int rad_digest_cmp(const uint8_t *a, const uint8_t *b, size_t length)
 }
 
 
-/*
- *     Validates the requesting client NAS.  Calculates the
+/**
+ * @brief Validates the requesting client NAS.  Calculates the
  *     signature based on the clients private key.
  */
 static int calc_acctdigest(RADIUS_PACKET *packet, const char *secret)
@@ -1828,8 +2014,8 @@ static int calc_acctdigest(RADIUS_PACKET *packet, const char *secret)
 }
 
 
-/*
- *     Validates the requesting client NAS.  Calculates the
+/**
+ * @brief Validates the requesting client NAS.  Calculates the
  *     signature based on the clients private key.
  */
 static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original,
@@ -1871,8 +2057,8 @@ static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original,
 }
 
 
-/*
- *     Check if a set of RADIUS formatted TLVs are OK.
+/**
+ * @brief Check if a set of RADIUS formatted TLVs are OK.
  */
 int rad_tlv_ok(const uint8_t *data, size_t length,
               size_t dv_type, size_t dv_length)
@@ -1958,8 +2144,8 @@ int rad_tlv_ok(const uint8_t *data, size_t length,
 }
 
 
-/*
- *     See if the data pointed to by PTR is a valid RADIUS packet.
+/**
+ * @brief See if the data pointed to by PTR is a valid RADIUS packet.
  *
  *     packet is not 'const * const' because we may update data_len,
  *     if there's more data in the UDP packet than in the RADIUS packet.
@@ -2269,8 +2455,8 @@ int rad_packet_ok(RADIUS_PACKET *packet, int flags)
 }
 
 
-/*
- *     Receive UDP client requests, and fill in
+/**
+ * @brief Receive UDP client requests, and fill in
  *     the basics of a RADIUS_PACKET structure.
  */
 RADIUS_PACKET *rad_recv(int fd, int flags)
@@ -2377,15 +2563,15 @@ RADIUS_PACKET *rad_recv(int fd, int flags)
        }
 
 #ifndef NDEBUG
-       if (fr_debug_flag > 3) rad_print_hex(packet);
+       if ((fr_debug_flag > 3) && fr_log_fp) rad_print_hex(packet);
 #endif
 
        return packet;
 }
 
 
-/*
- *     Verify the signature of a packet.
+/**
+ * @brief Verify the signature of a packet.
  */
 int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
               const char *secret)
@@ -2424,8 +2610,13 @@ int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
                        default:
                                break;
 
-                       case PW_ACCOUNTING_REQUEST:
                        case PW_ACCOUNTING_RESPONSE:
+                               if (original &&
+                                   (original->code == PW_STATUS_SERVER)) {
+                                       goto do_ack;
+                               }
+
+                       case PW_ACCOUNTING_REQUEST:
                        case PW_DISCONNECT_REQUEST:
                        case PW_DISCONNECT_ACK:
                        case PW_DISCONNECT_NAK:
@@ -2435,6 +2626,7 @@ int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
                                memset(packet->data + 4, 0, AUTH_VECTOR_LEN);
                                break;
 
+                       do_ack:
                        case PW_AUTHENTICATION_ACK:
                        case PW_AUTHENTICATION_REJECT:
                        case PW_ACCESS_CHALLENGE:
@@ -2554,8 +2746,8 @@ int rad_verify(RADIUS_PACKET *packet, RADIUS_PACKET *original,
 }
 
 
-/*
- *     Create a "raw" attribute from the attribute contents.
+/**
+ * @brief Create a "raw" attribute from the attribute contents.
  */
 static ssize_t data2vp_raw(UNUSED const RADIUS_PACKET *packet,
                           UNUSED const RADIUS_PACKET *original,
@@ -2579,12 +2771,13 @@ static ssize_t data2vp_raw(UNUSED const RADIUS_PACKET *packet,
        vp->length = length;
 
        /*
-        *      If the data is too large, mark it as a "TLV".
+        *      If it's short, put it into the array.  If it's too
+        *      long, flag it as such, and put it somewhere else;
         */
        if (length <= sizeof(vp->vp_octets)) {
                memcpy(vp->vp_octets, data, length);
        } else {
-               vp->type = PW_TYPE_TLV;
+               vp->type |= PW_FLAG_LONG;
                vp->vp_tlv = malloc(length);
                if (!vp->vp_tlv) {
                        pairfree(&vp);
@@ -2607,10 +2800,9 @@ static ssize_t data2vp_tlvs(const RADIUS_PACKET *packet,
                            const uint8_t *start, size_t length,
                            VALUE_PAIR **pvp);
 
-/*
- *     Create any kind of VP from the attribute contents.
- *
- *     Will return -1 on error, or "length".
+/**
+ * @brief Create any kind of VP from the attribute contents.
+ * @return -1 on error, or "length".
  */
 static ssize_t data2vp_any(const RADIUS_PACKET *packet,
                           const RADIUS_PACKET *original,
@@ -2622,6 +2814,7 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
        int data_offset = 0;
        DICT_ATTR *da;
        VALUE_PAIR *vp = NULL;
+       uint8_t buffer[256];
 
        if (length == 0) {
                /*
@@ -2665,6 +2858,31 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
        }
 
        /*
+        *      The data is very long.
+        */
+       if (length > sizeof(vp->vp_octets)) {
+               /*
+                *      Long encrypted attributes are forbidden.
+                */
+               if (da->flags.encrypt != FLAG_ENCRYPT_NONE) goto raw;
+
+#ifndef NDEBUG
+               /*
+                *      Catch programming errors.
+                */
+               if ((da->type != PW_TYPE_STRING) &&
+                   (da->type != PW_TYPE_OCTETS)) goto raw;
+
+#endif
+
+               /*
+                *      FIXME: Figure out how to deal with long
+                *      strings and binary data!
+                */
+               goto raw;
+       }
+
+       /*
         *      The attribute is known, and well formed.  We can now
         *      create it.  The main failure from here on in is being
         *      out of memory.
@@ -2695,28 +2913,29 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
        /*
         *      Copy the data to be decrypted
         */
-       vp->length = length - data_offset;
-       memcpy(&vp->vp_octets[0], data + data_offset, vp->length);
+       vp->length = length - data_offset;      
+       memcpy(buffer, data + data_offset, vp->length);
 
        /*
         *      Decrypt the attribute.
         */
-       switch (vp->flags.encrypt) {
+       if (secret && packet) switch (vp->flags.encrypt) {
                /*
                 *  User-Password
                 */
        case FLAG_ENCRYPT_USER_PASSWORD:
                if (original) {
-                       rad_pwdecode(vp->vp_strvalue,
+                       rad_pwdecode((char *) buffer,
                                     vp->length, secret,
                                     original->vector);
                } else {
-                       rad_pwdecode(vp->vp_strvalue,
+                       rad_pwdecode((char *) buffer,
                                     vp->length, secret,
                                     packet->vector);
                }
+               buffer[253] = '\0';
                if (vp->attribute == PW_USER_PASSWORD) {
-                       vp->length = strlen(vp->vp_strvalue);
+                       vp->length = strlen((char *) buffer);
                }
                break;
 
@@ -2727,7 +2946,7 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
        case FLAG_ENCRYPT_TUNNEL_PASSWORD:
                if (!original) goto raw;
 
-               if (rad_tunnel_pwdecode(vp->vp_octets, &vp->length,
+               if (rad_tunnel_pwdecode(buffer, &vp->length,
                                        secret, original->vector) < 0) {
                        goto raw;
                }
@@ -2745,10 +2964,10 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
                        make_secret(my_digest,
                                    original->vector,
                                    secret, data);
-                       memcpy(vp->vp_strvalue, my_digest,
+                       memcpy(buffer, my_digest,
                               AUTH_VECTOR_LEN );
-                       vp->vp_strvalue[AUTH_VECTOR_LEN] = '\0';
-                       vp->length = strlen(vp->vp_strvalue);
+                       buffer[AUTH_VECTOR_LEN] = '\0';
+                       vp->length = strlen((char *) buffer);
                }
                break;
 
@@ -2759,51 +2978,49 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
 
        switch (vp->type) {
        case PW_TYPE_STRING:
+               memcpy(vp->vp_strvalue, buffer, vp->length);
+               vp->vp_strvalue[vp->length] = '\0';
+               break;
+
        case PW_TYPE_OCTETS:
        case PW_TYPE_ABINARY:
-               /* nothing more to do */
+               memcpy(vp->vp_octets, buffer, vp->length);
                break;
 
        case PW_TYPE_BYTE:
                if (vp->length != 1) goto raw;
 
-               vp->vp_integer = vp->vp_octets[0];
+               vp->vp_integer = buffer[0];
                break;
 
 
        case PW_TYPE_SHORT:
                if (vp->length != 2) goto raw;
 
-               vp->vp_integer = (vp->vp_octets[0] << 8) | vp->vp_octets[1];
+               vp->vp_integer = (buffer[0] << 8) | buffer[1];
                break;
 
        case PW_TYPE_INTEGER:
                if (vp->length != 4) goto raw;
 
-               memcpy(&vp->vp_integer, vp->vp_octets, 4);
+               memcpy(&vp->vp_integer, buffer, 4);
                vp->vp_integer = ntohl(vp->vp_integer);
 
                if (vp->flags.has_tag) vp->vp_integer &= 0x00ffffff;
+               break;
 
-               /*
-                *      Try to get named VALUEs
-                */
-               {
-                       DICT_VALUE *dval;
-                       dval = dict_valbyattr(vp->attribute, vp->vendor,
-                                             vp->vp_integer);
-                       if (dval) {
-                               strlcpy(vp->vp_strvalue,
-                                       dval->name,
-                                       sizeof(vp->vp_strvalue));
-                       }
-               }
+       case PW_TYPE_INTEGER64:
+               if (vp->length != 8) goto raw;
+
+               /* vp_integer64 is a union with vp_octets */
+               memcpy(&vp->vp_integer64, buffer, 8);
+               vp->vp_integer64 = ntohll(vp->vp_integer64);
                break;
 
        case PW_TYPE_DATE:
                if (vp->length != 4) goto raw;
 
-               memcpy(&vp->vp_date, vp->vp_octets, 4);
+               memcpy(&vp->vp_date, buffer, 4);
                vp->vp_date = ntohl(vp->vp_date);
                break;
 
@@ -2811,7 +3028,7 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
        case PW_TYPE_IPADDR:
                if (vp->length != 4) goto raw;
 
-               memcpy(&vp->vp_ipaddr, vp->vp_octets, 4);
+               memcpy(&vp->vp_ipaddr, buffer, 4);
                break;
 
                /*
@@ -2819,7 +3036,7 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
                 */
        case PW_TYPE_IFID:
                if (vp->length != 8) goto raw;
-               /* vp->vp_ifid == vp->vp_octets */
+               memcpy(&vp->vp_ifid, buffer, 8);
                break;
 
                /*
@@ -2827,7 +3044,7 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
                 */
        case PW_TYPE_IPV6ADDR:
                if (vp->length != 16) goto raw;
-               /* vp->vp_ipv6addr == vp->vp_octets */
+               memcpy(&vp->vp_ipv6addr, buffer, 16);
                break;
 
                /*
@@ -2841,14 +3058,15 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
                 */
        case PW_TYPE_IPV6PREFIX:
                if (vp->length < 2 || vp->length > 18) goto raw;
-               if (vp->vp_octets[1] > 128) goto raw;
+               if (buffer[1] > 128) goto raw;
 
                /*
                 *      FIXME: double-check that
                 *      (vp->vp_octets[1] >> 3) matches vp->length + 2
                 */
+               memcpy(&vp->vp_ipv6prefix, buffer, vp->length);
                if (vp->length < 18) {
-                       memset(vp->vp_octets + vp->length, 0,
+                       memset(((uint8_t *)vp->vp_ipv6prefix) + vp->length, 0,
                               18 - vp->length);
                }
                break;
@@ -2860,9 +3078,8 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
                 *      Overload vp_integer for ntohl, which takes
                 *      uint32_t, not int32_t
                 */
-               memcpy(&vp->vp_integer, vp->vp_octets, 4);
+               memcpy(&vp->vp_integer, buffer, 4);
                vp->vp_integer = ntohl(vp->vp_integer);
-               memcpy(&vp->vp_signed, &vp->vp_integer, 4);
                break;
 
        case PW_TYPE_TLV:
@@ -2873,12 +3090,12 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
        case PW_TYPE_COMBO_IP:
                if (vp->length == 4) {
                        vp->type = PW_TYPE_IPADDR;
-                       memcpy(&vp->vp_ipaddr, vp->vp_octets, 4);
+                       memcpy(&vp->vp_ipaddr, buffer, 4);
                        break;
 
                } else if (vp->length == 16) {
                        vp->type = PW_TYPE_IPV6ADDR;
-                       /* vp->vp_ipv6addr == vp->vp_octets */
+                       memcpy(&vp->vp_ipv6addr, buffer, 16);
                        break;
 
                }
@@ -2894,8 +3111,8 @@ static ssize_t data2vp_any(const RADIUS_PACKET *packet,
 }
 
 
-/*
- *     Convert a top-level VSA to a VP.
+/**
+ * @brief Convert a top-level VSA to a VP.
  */
 static ssize_t attr2vp_vsa(const RADIUS_PACKET *packet,
                           const RADIUS_PACKET *original,
@@ -2981,8 +3198,8 @@ static ssize_t attr2vp_vsa(const RADIUS_PACKET *packet,
        return dv_type + dv_length + attrlen;
 }
 
-/*
- *     Convert one or more TLVs to VALUE_PAIRs.  This function can
+/**
+ * @brief Convert one or more TLVs to VALUE_PAIRs.  This function can
  *     be called recursively...
  */
 static ssize_t data2vp_tlvs(const RADIUS_PACKET *packet,
@@ -3125,8 +3342,9 @@ static ssize_t data2vp_tlvs(const RADIUS_PACKET *packet,
 }
 
 
-/*
- *     Group "continued" attributes together, and create VPs from them.
+/**
+ * @brief Group "continued" attributes together, and create VPs from them.
+ *
  *     The caller ensures that the RADIUS packet is OK, and that the
  *     continuations have all been checked.
  */
@@ -3164,6 +3382,7 @@ static ssize_t data2vp_continued(const RADIUS_PACKET *packet,
        while (left > 0) {
 #ifndef NDEBUG
                if (data >= (start + length)) {
+                       free(attr);
                        fr_strerror_printf("data2vp_continued: Internal sanity check failed");
                        return -1;
                }
@@ -3184,8 +3403,8 @@ static ssize_t data2vp_continued(const RADIUS_PACKET *packet,
 }
 
 
-/*
- *     Create a "raw" VALUE_PAIR from a RADIUS attribute.
+/**
+ * @brief Create a "raw" VALUE_PAIR from a RADIUS attribute.
  */
 ssize_t rad_attr2vp_raw(const RADIUS_PACKET *packet,
                        const RADIUS_PACKET *original,
@@ -3208,10 +3427,10 @@ ssize_t rad_attr2vp_raw(const RADIUS_PACKET *packet,
 }
 
 
-/*
- *     Get the length of the data portion of all of the contiguous
+/**
+ * @brief Get the length of the data portion of all of the contiguous
  *     continued attributes.
- *
+ * @return
  *     0 for "no continuation"
  *     -1 on malformed packets (continuation followed by non-wimax, etc.)
  */
@@ -3244,11 +3463,12 @@ static ssize_t wimax_attrlen(uint32_t vendor,
 }
 
 
-/*
- *     Get the length of the data portion of all of the contiguous
+/**
+ * @brief Get the length of the data portion of all of the contiguous
  *     continued attributes.
  *
- *     0 for "no continuation"
+ * @return
+ *     0 for "no continuation"
  *     -1 on malformed packets (continuation followed by non-wimax, etc.)
  */
 static ssize_t extended_attrlen(const uint8_t *start, const uint8_t *end)
@@ -3276,8 +3496,8 @@ static ssize_t extended_attrlen(const uint8_t *start, const uint8_t *end)
 }
 
 
-/*
- *     Create WiMAX VALUE_PAIRs from a RADIUS attribute.
+/**
+ * @brief Create WiMAX VALUE_PAIRs from a RADIUS attribute.
  */
 ssize_t rad_attr2vp_wimax(const RADIUS_PACKET *packet,
                          const RADIUS_PACKET *original,
@@ -3357,8 +3577,8 @@ ssize_t rad_attr2vp_wimax(const RADIUS_PACKET *packet,
        return data[1];
 }
 
-/*
- *     Create Vendor-Specifc VALUE_PAIRs from a RADIUS attribute.
+/**
+ * @brief Create Vendor-Specifc VALUE_PAIRs from a RADIUS attribute.
  */
 ssize_t rad_attr2vp_vsa(const RADIUS_PACKET *packet,
                        const RADIUS_PACKET *original,
@@ -3437,8 +3657,8 @@ ssize_t rad_attr2vp_vsa(const RADIUS_PACKET *packet,
        return data[1];
 }
 
-/*
- *     Create an "extended" VALUE_PAIR from a RADIUS attribute.
+/**
+ * @brief Create an "extended" VALUE_PAIR from a RADIUS attribute.
  */
 ssize_t rad_attr2vp_extended(const RADIUS_PACKET *packet,
                             const RADIUS_PACKET *original,
@@ -3571,8 +3791,8 @@ ssize_t rad_attr2vp_extended(const RADIUS_PACKET *packet,
 }
 
 
-/*
- *     Create a "standard" RFC VALUE_PAIR from the given data.
+/**
+ * @brief Create a "standard" RFC VALUE_PAIR from the given data.
  */
 ssize_t rad_attr2vp_rfc(const RADIUS_PACKET *packet,
                        const RADIUS_PACKET *original,
@@ -3593,8 +3813,8 @@ ssize_t rad_attr2vp_rfc(const RADIUS_PACKET *packet,
        return data[1];
 }      
 
-/*
- *     Create a "normal" VALUE_PAIR from the given data.
+/**
+ * @brief Create a "normal" VALUE_PAIR from the given data.
  */
 ssize_t rad_attr2vp(const RADIUS_PACKET *packet,
                    const RADIUS_PACKET *original,
@@ -3627,11 +3847,9 @@ ssize_t rad_attr2vp(const RADIUS_PACKET *packet,
 }
 
 
-/*
- *     Calculate/check digest, and decode radius attributes.
- *     Returns:
- *     -1 on decoding error
- *     0 on success
+/**
+ * @brief Calculate/check digest, and decode radius attributes.
+ * @return -1 on decoding error, 0 on success
  */
 int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
               const char *secret)
@@ -3720,8 +3938,8 @@ int rad_decode(RADIUS_PACKET *packet, RADIUS_PACKET *original,
 }
 
 
-/*
- *     Encode password.
+/**
+ * @brief Encode password.
  *
  *     We assume that the passwd buffer passed is big enough.
  *     RFC2138 says the password is max 128 chars, so the size
@@ -3793,8 +4011,8 @@ int rad_pwencode(char *passwd, size_t *pwlen, const char *secret,
        return 0;
 }
 
-/*
- *     Decode password.
+/**
+ * @brief Decode password.
  */
 int rad_pwdecode(char *passwd, size_t pwlen, const char *secret,
                 const uint8_t *vector)
@@ -3859,8 +4077,8 @@ int rad_pwdecode(char *passwd, size_t pwlen, const char *secret,
 }
 
 
-/*
- *     Encode Tunnel-Password attributes when sending them out on the wire.
+/**
+ * @brief Encode Tunnel-Password attributes when sending them out on the wire.
  *
  *     int *pwlen is updated to the new length of the encrypted
  *     password - a multiple of 16 bytes.
@@ -3944,8 +4162,8 @@ int rad_tunnel_pwencode(char *passwd, size_t *pwlen, const char *secret,
        return 0;
 }
 
-/*
- *     Decode Tunnel-Password encrypted attributes.
+/**
+ * @brief Decode Tunnel-Password encrypted attributes.
  *
  *      Defined in RFC-2868, this uses a two char SALT along with the
  *      initial intermediate value, to differentiate it from the
@@ -4050,10 +4268,10 @@ int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, const char *secret,
        return reallen;
 }
 
-/*
- *     Encode a CHAP password
+/**
+ * @brief Encode a CHAP password
  *
- *     FIXME: might not work with Ascend because
+ *     @bug FIXME: might not work with Ascend because
  *     we use vp->length, and Ascend gear likes
  *     to send an extra '\0' in the string!
  */
@@ -4108,8 +4326,8 @@ int rad_chap_encode(RADIUS_PACKET *packet, uint8_t *output, int id,
 }
 
 
-/*
- *     Seed the random number generator.
+/**
+ * @brief Seed the random number generator.
  *
  *     May be called any number of times.
  */
@@ -4162,8 +4380,8 @@ void fr_rand_seed(const void *data, size_t size)
 }
 
 
-/*
- *     Return a 32-bit random number.
+/**
+ * @brief Return a 32-bit random number.
  */
 uint32_t fr_rand(void)
 {
@@ -4186,8 +4404,8 @@ uint32_t fr_rand(void)
 }
 
 
-/*
- *     Allocate a new RADIUS_PACKET
+/**
+ * @brief Allocate a new RADIUS_PACKET
  */
 RADIUS_PACKET *rad_alloc(int newvector)
 {
@@ -4249,8 +4467,8 @@ RADIUS_PACKET *rad_alloc_reply(RADIUS_PACKET *packet)
 }
 
 
-/*
- *     Free a RADIUS_PACKET
+/**
+ * @brief Free a RADIUS_PACKET
  */
 void rad_free(RADIUS_PACKET **radius_packet_ptr)
 {