2 Copyright (c) 2011, Network RADIUS SARL
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7 * Redistributions of source code must retain the above copyright
8 notice, this list of conditions and the following disclaimer.
9 * Redistributions in binary form must reproduce the above copyright
10 notice, this list of conditions and the following disclaimer in the
11 documentation and/or other materials provided with the distribution.
12 * Neither the name of the <organization> nor the
13 names of its contributors may be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 * \brief Attribute encoding and decoding routines.
35 * Encodes the data portion of an attribute.
36 * Returns -1 on error, or the length of the data portion.
38 static ssize_t vp2data_any(const RADIUS_PACKET *packet,
39 const RADIUS_PACKET *original,
41 const VALUE_PAIR **pvp,
42 uint8_t *start, size_t room)
49 const VALUE_PAIR *vp = *pvp;
53 * See if we need to encode a TLV. The low portion of
54 * the attribute has already been placed into the packer.
55 * If there are still attribute bytes left, then go
56 * encode them as TLVs.
58 * If we cared about the stack, we could unroll the loop.
60 if ((nest > 0) && (nest <= nr_attr_max_tlv) &&
61 ((vp->da->attr >> nr_attr_shift[nest]) != 0)) {
62 return vp2data_tlvs(packet, original, nest, pvp,
66 nest = nest; /* -Wunused */
70 * Set up the default sources for the data.
75 switch(vp->da->type) {
76 case RS_TYPE_IPV6PREFIX:
77 len = sizeof(vp->vp_ipv6prefix);
83 case RS_TYPE_IPV6ADDR:
84 #ifdef RS_TYPE_ABINARY
87 /* nothing more to do */
91 len = 1; /* just in case */
92 array[0] = vp->vp_integer & 0xff;
97 len = 2; /* just in case */
98 array[0] = (vp->vp_integer >> 8) & 0xff;
99 array[1] = vp->vp_integer & 0xff;
103 case RS_TYPE_INTEGER:
104 len = 4; /* just in case */
105 lvalue = htonl(vp->vp_integer);
106 memcpy(array, &lvalue, sizeof(lvalue));
111 data = (const uint8_t *) &vp->vp_ipaddr;
112 len = 4; /* just in case */
116 * There are no tagged date attributes.
119 lvalue = htonl(vp->vp_date);
120 data = (const uint8_t *) &lvalue;
121 len = 4; /* just in case */
124 #ifdef VENDORPEC_WIMAX
129 len = 4; /* just in case */
130 slvalue = htonl(vp->vp_signed);
131 memcpy(array, &slvalue, sizeof(slvalue));
140 nr_debug_error("ERROR: Cannot encode NULL TLV");
147 default: /* unknown type: ignore it */
148 nr_debug_error("ERROR: Unknown attribute type %d", vp->da->type);
149 return -RSE_ATTR_TYPE_UNKNOWN;
153 * Bound the data to the calling size
155 if (len > (ssize_t) room) len = room;
157 #ifndef FLAG_ENCRYPT_TUNNEL_PASSWORD
158 original = original; /* -Wunused */
162 * Encrypt the various password styles
164 * Attributes with encrypted values MUST be less than
167 switch (vp->da->flags.encrypt) {
168 case FLAG_ENCRYPT_USER_PASSWORD:
169 len = nr_password_encrypt(ptr, room, data, len,
170 packet->secret, packet->vector);
173 #ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
174 case FLAG_ENCRYPT_TUNNEL_PASSWORD:
176 if (vp->da->flags.has_tag) lvalue = 1;
179 * Check if there's enough room. If there isn't,
180 * we discard the attribute.
182 * This is ONLY a problem if we have multiple VSA's
183 * in one Vendor-Specific, though.
185 if (room < (18 + lvalue)) {
190 switch (packet->code) {
191 case PW_ACCESS_ACCEPT:
192 case PW_ACCESS_REJECT:
193 case PW_ACCESS_CHALLENGE:
196 nr_debug_error("ERROR: No request packet, cannot encrypt %s attribute in the vp.", vp->da->name);
197 return -RSE_REQUEST_REQUIRED;
200 if (lvalue) ptr[0] = vp->tag;
201 len = nr_tunnelpw_encrypt(ptr + lvalue,
202 room - lvalue, data, len,
205 if (len < 0) return len;
207 case PW_ACCOUNTING_REQUEST:
208 case PW_DISCONNECT_REQUEST:
211 len = nr_tunnelpw_encrypt(ptr + 1, room, data, len - 1,
214 if (len < 0) return len;
221 * The code above ensures that this attribute
224 #ifdef FLAG_ENCRYPT_ASCEND_SECRET
225 case FLAG_ENCRYPT_ASCEND_SECRET:
226 make_secret(ptr, packet->vector, packet->secret, data);
227 len = AUTH_VECTOR_LEN;
232 if (vp->da->flags.has_tag && TAG_VALID(vp->tag)) {
233 if (vp->da->type == RS_TYPE_STRING) {
234 if (len > ((ssize_t) (room - 1))) len = room - 1;
237 } else if (vp->da->type == RS_TYPE_INTEGER) {
239 } /* else it can't be any other type */
241 memcpy(ptr, data, len);
243 } /* switch over encryption flags */
246 return len + (ptr - start);;
251 * Encode an RFC format TLV. This could be a standard attribute,
252 * or a TLV data type. If it's a standard attribute, then
253 * vp->da->attr == attribute. Otherwise, attribute may be
256 static ssize_t vp2attr_rfc(const RADIUS_PACKET *packet,
257 const RADIUS_PACKET *original,
258 const VALUE_PAIR **pvp,
259 unsigned int attribute, uint8_t *ptr, size_t room)
268 ptr[0] = attribute & 0xff;
271 if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
273 len = vp2data_any(packet, original, 0, pvp, ptr + ptr[1], room);
274 if (len < 0) return len;
284 * Encode a VSA which is a TLV. If it's in the RFC format, call
285 * vp2attr_rfc. Otherwise, encode it here.
287 static ssize_t vp2attr_vsa(const RADIUS_PACKET *packet,
288 const RADIUS_PACKET *original,
289 const VALUE_PAIR **pvp,
290 unsigned int attribute, unsigned int vendor,
291 uint8_t *ptr, size_t room)
294 const DICT_VENDOR *dv;
297 * Unknown vendor: RFC format.
298 * Known vendor and RFC format: go do that.
300 dv = nr_dict_vendor_byvalue(vendor);
304 !(*pvp)->flags.is_tlv &&
306 (dv->type == 1) && (dv->length == 1))) {
307 return vp2attr_rfc(packet, original, pvp,
308 attribute, ptr, room);
312 if ((*pvp)->flags.is_tlv) {
313 return data2vp_tlvs(packet, original, 0, pvp,
320 nr_debug_error("vp2attr_vsa: Internal sanity check failed,"
321 " type %u", (unsigned) dv->type);
322 return -RSE_INTERNAL;
325 ptr[0] = 0; /* attr must be 24-bit */
326 ptr[1] = (attribute >> 16) & 0xff;
327 ptr[2] = (attribute >> 8) & 0xff;
328 ptr[3] = attribute & 0xff;
332 ptr[0] = (attribute >> 8) & 0xff;
333 ptr[1] = attribute & 0xff;
337 ptr[0] = attribute & 0xff;
341 switch (dv->length) {
343 nr_debug_error("vp2attr_vsa: Internal sanity check failed,"
344 " length %u", (unsigned) dv->length);
345 return -RSE_INTERNAL;
355 ptr[dv->type + dv->length - 1] = dv->type + dv->length;
360 if (room > ((unsigned) 255 - (dv->type + dv->length))) {
361 room = 255 - (dv->type + dv->length);
364 len = vp2data_any(packet, original, 0, pvp,
365 ptr + dv->type + dv->length, room);
366 if (len < 0) return len;
368 if (dv->length) ptr[dv->type + dv->length - 1] += len;
370 return dv->type + dv->length + len;
375 * Encode a Vendor-Specific attribute.
377 ssize_t nr_vp2vsa(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
378 const VALUE_PAIR **pvp, uint8_t *ptr,
383 const VALUE_PAIR *vp = *pvp;
385 #ifdef VENDORPEC_WIMAX
387 * Double-check for WiMAX
389 if (vp->da->vendor == VENDORPEC_WIMAX) {
390 return nr_vp2wimax(packet, original, pvp,
395 if (vp->da->vendor > RS_MAX_VENDOR) {
396 nr_debug_error("nr_vp2vsa: Invalid arguments");
401 * Not enough room for:
402 * attr, len, vendor-id
410 * Build the Vendor-Specific header
412 ptr[0] = PW_VENDOR_SPECIFIC;
414 lvalue = htonl(vp->da->vendor);
415 memcpy(ptr + 2, &lvalue, 4);
417 if (room > ((unsigned) 255 - ptr[1])) room = 255 - ptr[1];
419 len = vp2attr_vsa(packet, original, pvp,
420 vp->da->attr, vp->da->vendor,
422 if (len < 0) return len;
432 * Encode an RFC standard attribute 1..255
434 ssize_t nr_vp2rfc(const RADIUS_PACKET *packet,
435 const RADIUS_PACKET *original,
436 const VALUE_PAIR **pvp,
437 uint8_t *ptr, size_t room)
439 const VALUE_PAIR *vp = *pvp;
441 if (vp->da->vendor != 0) {
442 nr_debug_error("nr_vp2rfc called with VSA");
446 if ((vp->da->attr == 0) || (vp->da->attr > 255)) {
447 nr_debug_error("nr_vp2rfc called with non-standard attribute %u", vp->da->attr);
451 #ifdef PW_CHARGEABLE_USER_IDENTITY
452 if ((vp->length == 0) &&
453 (vp->da != RS_DA_CHARGEABLE_USER_IDENTITY)) {
459 return vp2attr_rfc(packet, original, pvp, vp->da->attr,
463 #ifdef PW_CHAP_PASSWORD
465 * Encode an RFC standard attribute 1..255
467 static ssize_t nr_chap2rfc(const RADIUS_PACKET *packet,
468 const RADIUS_PACKET *original,
469 const VALUE_PAIR **pvp,
470 uint8_t *ptr, size_t room)
473 const VALUE_PAIR *vp = *pvp;
475 uint8_t buffer[RS_MAX_STRING_LEN*2 + 1], *p;
483 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
488 if ((vp->da->vendor != 0) || (vp->da != RS_DA_CHAP_PASSWORD)) {
489 nr_debug_error("nr_chap2rfc called with non-CHAP");
494 *(p++) = nr_rand() & 0xff; /* id */
496 memcpy(p, vp->vp_strvalue, strlen(vp->vp_strvalue));
497 p += strlen(vp->vp_strvalue);
499 vp = nr_vps_find(packet->vps, PW_CHAP_CHALLENGE, 0);
501 memcpy(p, vp->vp_octets, vp->length);
504 memcpy(p, packet->vector, sizeof(packet->vector));
505 p += sizeof(packet->vector);
509 RS_MD5Update(&ctx, buffer, p - buffer);
510 RS_MD5Final(&chap.vp_octets[1], &ctx);
512 chap.vp_octets[0] = buffer[0];
515 rcode = vp2attr_rfc(packet, original, &vp, chap.da->attr,
517 if (rcode < 0) return rcode;
522 #endif /* PW_CHAP_PASSWORD */
524 #ifdef PW_MESSAGE_AUTHENTICATOR
525 /** Fake Message-Authenticator.
527 * This structure is used to replace a Message-Authenticator in the
528 * input list of VALUE_PAIRs when encoding a packet. If the caller
529 * asks us to encode a Message-Authenticator, we ignore the one given
530 * to us by the caller (which may have the wrong length, etc.), and
531 * instead use this one, which has the correct length and data.
533 static const VALUE_PAIR fake_ma = {
534 RS_DA_MESSAGE_AUTHENTICATOR,
540 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
544 #endif /* PW_MESSAGE_AUTHENTICATOR */
547 * Parse a data structure into a RADIUS attribute.
549 ssize_t nr_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,
550 const VALUE_PAIR **pvp, uint8_t *start,
553 const VALUE_PAIR *vp = *pvp;
556 * RFC format attributes take the fast path.
558 if (vp->da->vendor != 0) {
559 #ifdef VENDORPEC_EXTENDED
560 if (vp->da->vendor > RS_MAX_VENDOR) {
561 return nr_vp2attr_extended(packet, original,
567 #ifdef VENDORPEC_WIMAX
568 if (vp->da->vendor == VENDORPEC_WIMAX) {
569 return nr_vp2attr_wimax(packet, original,
575 return nr_vp2vsa(packet, original, pvp, start, room);
577 nr_debug_error("VSAs are not supported");
578 return -RSE_UNSUPPORTED;
583 * Ignore non-protocol attributes.
585 if (vp->da->attr > 255) {
590 #ifdef PW_MESSAGE_AUTHENTICATOR
592 * The caller wants a Message-Authenticator, but doesn't
593 * know how to calculate it, or what the correct values
594 * are. So... create one for him.
596 if (vp->da == RS_DA_MESSAGE_AUTHENTICATOR) {
600 rcode = nr_vp2rfc(packet, original, &vp, start, room);
601 if (rcode <= 0) return rcode;
607 #ifdef PW_CHAP_PASSWORD
609 * The caller wants a CHAP-Password, but doesn't know how
610 * to calculate it, or what the correct values are. To
611 * help, we calculate it for him.
613 if (vp->da == RS_DA_CHAP_PASSWORD) {
617 * CHAP is ID + MD5(...). If it's length is NOT
618 * 17, then the caller has passed us a password,
619 * and wants us to encode it. If the length IS
620 * 17, then we need to double-check if the caller
621 * has already encoded it.
623 if (vp->length == 17) {
627 * ASCII and UTF-8 disallow values 0..31.
628 * If they appear, then the CHAP-Password
629 * has already been encoded by the
630 * caller. The probability of a
631 * CHAP-Password being all 32..256 is
632 * (1-32/256)^17 =~ .10
634 * This check isn't perfect, but it
635 * should be pretty rare for people to
636 * have 17-character passwords *and* have
639 for (i = 0; i < 17; i++) {
640 if (vp->vp_octets[i] < 32) {
648 return nr_chap2rfc(packet, original, pvp, start, room);
653 return nr_vp2rfc(packet, original, pvp,
659 * Ignore unknown attributes, but "decoding" them into nothing.
661 static ssize_t data2vp_raw(UNUSED const RADIUS_PACKET *packet,
662 UNUSED const RADIUS_PACKET *original,
663 unsigned int attribute,
665 const uint8_t *data, size_t length,
670 if (length > sizeof(vp->vp_octets)) return -RSE_ATTR_OVERFLOW;
672 vp = nr_vp_alloc_raw(attribute, vendor);
673 if (!vp) return -RSE_NOMEM;
675 memcpy(vp->vp_octets, data, length);
682 ssize_t nr_attr2vp_raw(const RADIUS_PACKET *packet,
683 const RADIUS_PACKET *original,
684 const uint8_t *data, size_t length,
688 if (length < 2) return -RSE_PACKET_TOO_SMALL;
689 if (data[1] < 2) return -RSE_ATTR_TOO_SMALL;
690 if (data[1] > length) return -RSE_ATTR_OVERFLOW;
692 return data2vp_raw(packet, original, data[0], 0,
693 data + 2, data[1] - 2, pvp);
697 * Create any kind of VP from the attribute contents.
699 * Will return -1 on error, or "length".
701 static ssize_t data2vp_any(const RADIUS_PACKET *packet,
702 const RADIUS_PACKET *original,
704 unsigned int attribute, unsigned int vendor,
705 const uint8_t *data, size_t length,
708 #ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
713 VALUE_PAIR *vp = NULL;
717 * Hacks for CUI. The WiMAX spec says that it
718 * can be zero length, even though this is
719 * forbidden by the RADIUS specs. So... we make
720 * a special case for it.
723 (attribute == PW_CHARGEABLE_USER_IDENTITY)) {
724 data = (const uint8_t *) "";
732 da = nr_dict_attr_byvalue(attribute, vendor);
735 * Unknown attribute. Create it as a "raw" attribute.
739 if (vp) nr_vp_free(&vp);
740 return data2vp_raw(packet, original,
741 attribute, vendor, data, length, pvp);
746 * TLVs are handled first. They can't be tagged, and
747 * they can't be encrypted.
749 if (da->da->type == RS_TYPE_TLV) {
750 return data2vp_tlvs(packet, original,
751 attribute, vendor, nest,
755 nest = nest; /* -Wunused */
759 * The attribute is known, and well formed. We can now
760 * create it. The main failure from here on in is being
763 vp = nr_vp_alloc(da);
764 if (!vp) return -RSE_NOMEM;
769 if (vp->da->flags.has_tag) {
770 if (TAG_VALID(data[0])
771 #ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
772 || (vp->da->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD)
776 * Tunnel passwords REQUIRE a tag, even
777 * if don't have a valid tag.
781 if ((vp->da->type == RS_TYPE_STRING) ||
782 (vp->da->type == RS_TYPE_OCTETS)) {
783 if (length == 0) goto raw;
790 * Copy the data to be decrypted
792 vp->length = length - data_offset;
793 memcpy(&vp->vp_octets[0], data + data_offset, vp->length);
796 * Decrypt the attribute.
798 switch (vp->da->flags.encrypt) {
802 case FLAG_ENCRYPT_USER_PASSWORD:
804 rcode = nr_password_encrypt(vp->vp_octets,
805 sizeof(vp->vp_strvalue),
806 data + data_offset, vp->length,
810 rcode = nr_password_encrypt(vp->vp_octets,
811 sizeof(vp->vp_strvalue),
812 data + data_offset, vp->length,
816 if (rcode < 0) goto raw;
817 vp->vp_strvalue[128] = '\0';
818 vp->length = strlen(vp->vp_strvalue);
822 * Tunnel-Password's may go ONLY
823 * in response packets.
825 #ifdef FLAG_ENCRYPT_TUNNEL_PASSWORD
826 case FLAG_ENCRYPT_TUNNEL_PASSWORD:
827 if (!original) goto raw;
829 rcode = nr_tunnelpw_decrypt(vp->vp_octets,
830 sizeof(vp->vp_octets),
831 data + data_offset, vp->length,
832 packet->secret, original->vector);
833 if (rcode < 0) goto raw;
839 #ifdef FLAG_ENCRYPT_ASCEND_SECRET:
842 * Ascend-Receive-Secret
844 case FLAG_ENCRYPT_ASCEND_SECRET:
848 uint8_t my_digest[AUTH_VECTOR_LEN];
849 make_secret(my_digest,
851 packet->secret, data);
852 memcpy(vp->vp_strvalue, my_digest,
854 vp->vp_strvalue[AUTH_VECTOR_LEN] = '\0';
855 vp->length = strlen(vp->vp_strvalue);
862 } /* switch over encryption flags */
865 * Expected a certain length, but got something else.
867 if ((vp->da->flags.length != 0) &&
868 (vp->length != vp->da->flags.length)) {
872 switch (vp->da->type) {
875 #ifdef RS_TYPE_ABINARY
876 case RS_TYPE_ABINARY:
878 /* nothing more to do */
882 vp->vp_integer = vp->vp_octets[0];
887 vp->vp_integer = (vp->vp_octets[0] << 8) | vp->vp_octets[1];
890 case RS_TYPE_INTEGER:
891 memcpy(&vp->vp_integer, vp->vp_octets, 4);
892 vp->vp_integer = ntohl(vp->vp_integer);
894 if (vp->da->flags.has_tag) vp->vp_integer &= 0x00ffffff;
898 memcpy(&vp->vp_date, vp->vp_octets, 4);
899 vp->vp_date = ntohl(vp->vp_date);
904 memcpy(&vp->vp_ipaddr, vp->vp_octets, 4);
908 * IPv6 interface ID is 8 octets long.
911 /* vp->vp_ifid == vp->vp_octets */
915 * IPv6 addresses are 16 octets long
917 case RS_TYPE_IPV6ADDR:
918 /* vp->vp_ipv6addr == vp->vp_octets */
922 * IPv6 prefixes are 2 to 18 octets long.
924 * RFC 3162: The first octet is unused.
925 * The second is the length of the prefix
926 * the rest are the prefix data.
928 * The prefix length can have value 0 to 128.
930 case RS_TYPE_IPV6PREFIX:
931 if (vp->length < 2 || vp->length > 18) goto raw;
932 if (vp->vp_octets[1] > 128) goto raw;
935 * FIXME: double-check that
936 * (vp->vp_octets[1] >> 3) matches vp->length + 2
938 if (vp->length < 18) {
939 memset(vp->vp_octets + vp->length, 0,
944 #ifdef VENDORPEC_WIMAX
946 if (vp->length != 4) goto raw;
949 * Overload vp_integer for ntohl, which takes
950 * uint32_t, not int32_t
952 memcpy(&vp->vp_integer, vp->vp_octets, 4);
953 vp->vp_integer = ntohl(vp->vp_integer);
954 memcpy(&vp->vp_signed, &vp->vp_integer, 4);
961 nr_debug_error("data2vp_any: Internal sanity check failed");
962 return -RSE_ATTR_TYPE_UNKNOWN;
965 #ifdef VENDORPEC_WIMAX
966 case RS_TYPE_COMBO_IP:
967 if (vp->length == 4) {
968 vp->da->type = RS_TYPE_IPADDR;
969 memcpy(&vp->vp_ipaddr, vp->vp_octets, 4);
972 } else if (vp->length == 16) {
973 vp->da->type = RS_TYPE_IPV6ADDR;
974 /* vp->vp_ipv6addr == vp->vp_octets */
992 * Create a "standard" RFC VALUE_PAIR from the given data.
994 ssize_t nr_attr2vp_rfc(const RADIUS_PACKET *packet,
995 const RADIUS_PACKET *original,
996 const uint8_t *data, size_t length,
1001 if (length < 2) return -RSE_PACKET_TOO_SMALL;
1002 if (data[1] < 2) return -RSE_ATTR_TOO_SMALL;
1003 if (data[1] > length) return -RSE_ATTR_OVERFLOW;
1005 rcode = data2vp_any(packet, original, 0,
1006 data[0], 0, data + 2, data[1] - 2, pvp);
1007 if (rcode < 0) return rcode;
1012 #ifndef WITHOUT_VSAS
1014 * Check if a set of RADIUS formatted TLVs are OK.
1016 int nr_tlv_ok(const uint8_t *data, size_t length,
1017 size_t dv_type, size_t dv_length)
1019 const uint8_t *end = data + length;
1021 if ((dv_length > 2) || (dv_type == 0) || (dv_type > 4)) {
1022 nr_debug_error("nr_tlv_ok: Invalid arguments");
1026 while (data < end) {
1029 if ((data + dv_type + dv_length) > end) {
1030 nr_debug_error("Attribute header overflow");
1031 return -RSE_ATTR_TOO_SMALL;
1036 if ((data[0] == 0) && (data[1] == 0) &&
1037 (data[2] == 0) && (data[3] == 0)) {
1039 nr_debug_error("Invalid attribute 0");
1040 return -RSE_ATTR_INVALID;
1044 nr_debug_error("Invalid attribute > 2^24");
1045 return -RSE_ATTR_INVALID;
1050 if ((data[1] == 0) && (data[1] == 0)) goto zero;
1054 if (data[0] == 0) goto zero;
1058 nr_debug_error("Internal sanity check failed");
1059 return -RSE_INTERNAL;
1062 switch (dv_length) {
1067 if (data[dv_type + 1] != 0) {
1068 nr_debug_error("Attribute is longer than 256 octets");
1069 return -RSE_ATTR_TOO_LARGE;
1073 attrlen = data[dv_type + dv_length - 1];
1078 nr_debug_error("Internal sanity check failed");
1079 return -RSE_INTERNAL;
1082 if (attrlen < (dv_type + dv_length)) {
1083 nr_debug_error("Attribute header has invalid length");
1084 return -RSE_PACKET_TOO_SMALL;
1087 if (attrlen > length) {
1088 nr_debug_error("Attribute overflows container");
1089 return -RSE_ATTR_OVERFLOW;
1101 * Convert a top-level VSA to a VP.
1103 static ssize_t attr2vp_vsa(const RADIUS_PACKET *packet,
1104 const RADIUS_PACKET *original,
1105 unsigned int vendor,
1106 size_t dv_type, size_t dv_length,
1107 const uint8_t *data, size_t length,
1110 unsigned int attribute;
1111 ssize_t attrlen, my_len;
1114 if (length <= (dv_type + dv_length)) {
1115 nr_debug_error("attr2vp_vsa: Failure to call nr_tlv_ok");
1116 return -RSE_PACKET_TOO_SMALL;
1122 /* data[0] must be zero */
1123 attribute = data[1] << 16;
1124 attribute |= data[2] << 8;
1125 attribute |= data[3];
1129 attribute = data[0] << 8;
1130 attribute |= data[1];
1134 attribute = data[0];
1138 nr_debug_error("attr2vp_vsa: Internal sanity check failed");
1139 return -RSE_INTERNAL;
1142 switch (dv_length) {
1144 /* data[dv_type] must be zero */
1145 attrlen = data[dv_type + 1];
1149 attrlen = data[dv_type];
1157 nr_debug_error("attr2vp_vsa: Internal sanity check failed");
1158 return -RSE_INTERNAL;
1162 if (attrlen <= (ssize_t) (dv_type + dv_length)) {
1163 nr_debug_error("attr2vp_vsa: Failure to call nr_tlv_ok");
1164 return -RSE_PACKET_TOO_SMALL;
1168 attrlen -= (dv_type + dv_length);
1170 my_len = data2vp_any(packet, original, 0,
1172 data + dv_type + dv_length, attrlen, pvp);
1173 if (my_len < 0) return my_len;
1176 if (my_len != attrlen) {
1178 nr_debug_error("attr2vp_vsa: Incomplete decode %d != %d",
1179 (int) my_len, (int) attrlen);
1180 return -RSE_INTERNAL;
1184 return dv_type + dv_length + attrlen;
1189 * Create Vendor-Specifc VALUE_PAIRs from a RADIUS attribute.
1191 ssize_t nr_attr2vp_vsa(const RADIUS_PACKET *packet,
1192 const RADIUS_PACKET *original,
1193 const uint8_t *data, size_t length,
1196 size_t dv_type, dv_length;
1199 const DICT_VENDOR *dv;
1201 if (length < 2) return -RSE_PACKET_TOO_SMALL;
1202 if (data[1] < 2) return -RSE_ATTR_TOO_SMALL;
1203 if (data[1] > length) return -RSE_ATTR_OVERFLOW;
1205 if (data[0] != PW_VENDOR_SPECIFIC) {
1206 nr_debug_error("nr_attr2vp_vsa: Invalid attribute");
1211 * Not enough room for a Vendor-Id.
1212 * Or the high octet of the Vendor-Id is set.
1214 if ((data[1] < 6) || (data[2] != 0)) {
1215 return nr_attr2vp_raw(packet, original,
1219 memcpy(&lvalue, data + 2, 4);
1220 lvalue = ntohl(lvalue);
1222 #ifdef VENDORPEC_WIMAX
1224 * WiMAX gets its own set of magic.
1226 if (lvalue == VENDORPEC_WIMAX) {
1227 return nr_attr2vp_wimax(packet, original,
1232 dv_type = dv_length = 1;
1233 dv = nr_dict_vendor_byvalue(lvalue);
1235 return nr_attr2vp_rfc(packet, original,
1240 dv_length = dv->length;
1243 * Attribute is not in the correct form.
1245 if (nr_tlv_ok(data + 6, data[1] - 6, dv_type, dv_length) < 0) {
1246 return nr_attr2vp_raw(packet, original,
1250 my_len = attr2vp_vsa(packet, original,
1251 lvalue, dv_type, dv_length,
1252 data + 6, data[1] - 6, pvp);
1253 if (my_len < 0) return my_len;
1256 if (my_len != (data[1] - 6)) {
1258 nr_debug_error("nr_attr2vp_vsa: Incomplete decode");
1259 return -RSE_INTERNAL;
1265 #endif /* WITHOUT_VSAS */
1269 * Create a "normal" VALUE_PAIR from the given data.
1271 ssize_t nr_attr2vp(const RADIUS_PACKET *packet,
1272 const RADIUS_PACKET *original,
1273 const uint8_t *data, size_t length,
1276 if (length < 2) return -RSE_PACKET_TOO_SMALL;
1277 if (data[1] < 2) return -RSE_ATTR_TOO_SMALL;
1278 if (data[1] > length) return -RSE_ATTR_OVERFLOW;
1280 #ifndef WITHOUT_VSAS
1282 * VSAs get their own handler.
1284 if (data[0] == PW_VENDOR_SPECIFIC) {
1285 return nr_attr2vp_vsa(packet, original,
1290 #ifdef VENDORPEC_EXTENDED
1292 * Extended attribute format gets their own handler.
1294 if (nr_dict_attr_byvalue(data[0], VENDORPEC_EXTENDED) != NULL) {
1295 return nr_attr2vp_extended(packet, original,
1300 return nr_attr2vp_rfc(packet, original, data, length, pvp);
1303 ssize_t nr_attr2data(const RADIUS_PACKET *packet, ssize_t start,
1304 unsigned int attribute, unsigned int vendor,
1305 const uint8_t **pdata, size_t *plength)
1307 uint8_t *data, *attr;
1310 if (!packet || !pdata || !plength) return -RSE_INVAL;
1312 if (!packet->data) return -RSE_INVAL;
1313 if (packet->length < 20) return -RSE_INVAL;
1316 * Too long or short, not good.
1319 ((start > 0) && (start < 20))) return -RSE_INVAL;
1321 if ((size_t) start >= (packet->length - 2)) return -RSE_INVAL;
1323 end = packet->data + packet->length;
1326 * Loop over the packet, converting attrs to VPs.
1329 data = packet->data + 20;
1331 data = packet->data + start;
1333 if (data >= end) return 0;
1336 for (attr = data; attr < end; attr += attr[1]) {
1337 const DICT_VENDOR *dv = NULL;
1341 * This code is copied from packet_ok().
1342 * It could be put into a separate function.
1344 if ((attr + 2) > end) {
1345 nr_debug_error("Attribute overflows packet");
1346 return -RSE_ATTR_OVERFLOW;
1350 nr_debug_error("Attribute length is too small");
1351 return -RSE_ATTR_TOO_SMALL;
1354 if ((attr + attr[1]) > end) {
1355 nr_debug_error("Attribute length is too large");
1356 return -RSE_ATTR_TOO_LARGE;
1360 if ((vendor == 0) && (attr[0] == attribute)) {
1362 *plength = attr[1] - 2;
1363 return attr - packet->data;
1366 #ifndef WITHOUT_VSAS
1370 if (attr[0] != PW_VENDOR_SPECIFIC) continue;
1372 if (attr[1] < 6) continue;
1374 memcpy(&vendorpec, attr + 2, 4);
1375 vendorpec = ntohl(vendorpec);
1376 if (vendor != vendorpec) continue;
1379 dv = nr_dict_vendor_byvalue(vendor);
1381 ((dv->type != 1) || (dv->length != 1))) {
1382 return -RSE_VENDOR_UNKNOWN;
1389 if (attr[1] < 9) continue;
1392 * Malformed, or more than one VSA in
1393 * the Vendor-Specific
1395 if (attr[7] + 6 != attr[1]) continue;
1398 * Not the right VSA.
1400 if (attr[6] != attribute) continue;
1403 *plength = attr[1] - 8;
1404 return attr - packet->data;
1409 return 0; /* nothing more: stop */