xref: /openbsd-src/lib/libradius/radius_attr.c (revision 834c20a7b5c2a65cf5762aa69a1d44b3ff24e960)
1*834c20a7Syasuoka /*	$OpenBSD: radius_attr.c,v 1.3 2024/07/24 08:19:16 yasuoka Exp $ */
20eaf192dSyasuoka 
30eaf192dSyasuoka /*-
40eaf192dSyasuoka  * Copyright (c) 2009 Internet Initiative Japan Inc.
50eaf192dSyasuoka  * All rights reserved.
60eaf192dSyasuoka  *
70eaf192dSyasuoka  * Redistribution and use in source and binary forms, with or without
80eaf192dSyasuoka  * modification, are permitted provided that the following conditions
90eaf192dSyasuoka  * are met:
100eaf192dSyasuoka  * 1. Redistributions of source code must retain the above copyright
110eaf192dSyasuoka  *    notice, this list of conditions and the following disclaimer.
120eaf192dSyasuoka  * 2. Redistributions in binary form must reproduce the above copyright
130eaf192dSyasuoka  *    notice, this list of conditions and the following disclaimer in the
140eaf192dSyasuoka  *    documentation and/or other materials provided with the distribution.
150eaf192dSyasuoka  *
160eaf192dSyasuoka  * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
170eaf192dSyasuoka  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
180eaf192dSyasuoka  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
190eaf192dSyasuoka  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
200eaf192dSyasuoka  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
210eaf192dSyasuoka  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
220eaf192dSyasuoka  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
230eaf192dSyasuoka  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
240eaf192dSyasuoka  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
250eaf192dSyasuoka  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
260eaf192dSyasuoka  * SUCH DAMAGE.
270eaf192dSyasuoka  */
280eaf192dSyasuoka 
290eaf192dSyasuoka #include <netinet/in.h>
307426d5d9Syasuoka #include <arpa/inet.h>
310eaf192dSyasuoka 
327426d5d9Syasuoka #include <endian.h>
330eaf192dSyasuoka #include <stdbool.h>
347426d5d9Syasuoka #include <stdint.h>
350eaf192dSyasuoka #include <stdio.h>
360eaf192dSyasuoka #include <string.h>
370eaf192dSyasuoka 
380eaf192dSyasuoka #include "radius.h"
390eaf192dSyasuoka 
400eaf192dSyasuoka #include "radius_local.h"
410eaf192dSyasuoka 
420eaf192dSyasuoka #define FIND_ATTRIBUTE_BEGIN(constness, redolabel)		\
430eaf192dSyasuoka 	constness RADIUS_ATTRIBUTE* attr;			\
440eaf192dSyasuoka 	constness RADIUS_ATTRIBUTE* end;			\
450eaf192dSyasuoka 								\
460eaf192dSyasuoka 	attr = ATTRS_BEGIN(packet->pdata);			\
470eaf192dSyasuoka 	end  = ATTRS_END(packet->pdata);			\
480eaf192dSyasuoka 								\
490eaf192dSyasuoka 	for (;; ATTRS_ADVANCE(attr))				\
500eaf192dSyasuoka 	{							\
510eaf192dSyasuoka 	redolabel						\
520eaf192dSyasuoka 		if (attr >= end)				\
530eaf192dSyasuoka 			break;					\
540eaf192dSyasuoka 		if (attr->type != type)				\
550eaf192dSyasuoka 			continue;				\
560eaf192dSyasuoka 		{
570eaf192dSyasuoka 
580eaf192dSyasuoka #define FIND_ATTRIBUTE_END \
590eaf192dSyasuoka 	} }
600eaf192dSyasuoka 
610eaf192dSyasuoka #define FIND_VS_ATTRIBUTE_BEGIN(constness, redolabel)		\
620eaf192dSyasuoka 	constness RADIUS_ATTRIBUTE* attr;			\
630eaf192dSyasuoka 	constness RADIUS_ATTRIBUTE* end;			\
640eaf192dSyasuoka 								\
650eaf192dSyasuoka 	attr = ATTRS_BEGIN(packet->pdata);			\
660eaf192dSyasuoka 	end  = ATTRS_END(packet->pdata);			\
670eaf192dSyasuoka 								\
680eaf192dSyasuoka 	for (;; ATTRS_ADVANCE(attr))				\
690eaf192dSyasuoka 	{							\
700eaf192dSyasuoka 	redolabel						\
710eaf192dSyasuoka 		if (attr >= end)				\
720eaf192dSyasuoka 			break;					\
730eaf192dSyasuoka 		if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC)	\
740eaf192dSyasuoka 			continue;				\
750eaf192dSyasuoka 		if (attr->vendor != htonl(vendor))		\
760eaf192dSyasuoka 			continue;				\
770eaf192dSyasuoka 		if (attr->vtype != vtype)			\
780eaf192dSyasuoka 			continue;				\
790eaf192dSyasuoka 		{
800eaf192dSyasuoka 
810eaf192dSyasuoka #define FIND_VS_ATTRIBUTE_END					\
820eaf192dSyasuoka 	} }
830eaf192dSyasuoka 
840eaf192dSyasuoka 
850eaf192dSyasuoka int
860eaf192dSyasuoka radius_get_raw_attr_ptr(const RADIUS_PACKET * packet, uint8_t type,
870eaf192dSyasuoka     const void **ptr, size_t * length)
880eaf192dSyasuoka {
890eaf192dSyasuoka 	FIND_ATTRIBUTE_BEGIN(const,) {
900eaf192dSyasuoka 		*length = attr->length - 2;
910eaf192dSyasuoka 		*ptr = attr->data;
920eaf192dSyasuoka 		return (0);
930eaf192dSyasuoka 	} FIND_ATTRIBUTE_END;
940eaf192dSyasuoka 
950eaf192dSyasuoka 	return (-1);
960eaf192dSyasuoka }
970eaf192dSyasuoka 
980eaf192dSyasuoka int
990eaf192dSyasuoka radius_get_vs_raw_attr_ptr(const RADIUS_PACKET * packet, uint32_t vendor,
1000eaf192dSyasuoka     uint8_t vtype, const void **ptr, size_t * length)
1010eaf192dSyasuoka {
1020eaf192dSyasuoka 	FIND_VS_ATTRIBUTE_BEGIN(const,) {
1030eaf192dSyasuoka 		*length = attr->vlength - 2;
1040eaf192dSyasuoka 		*ptr = attr->vdata;
1050eaf192dSyasuoka 		return (0);
1060eaf192dSyasuoka 	} FIND_VS_ATTRIBUTE_END;
1070eaf192dSyasuoka 
1080eaf192dSyasuoka 	return (-1);
1090eaf192dSyasuoka }
1100eaf192dSyasuoka 
1110eaf192dSyasuoka int
1120eaf192dSyasuoka radius_get_raw_attr(const RADIUS_PACKET * packet, uint8_t type, void *buf,
1130eaf192dSyasuoka     size_t * length)
1140eaf192dSyasuoka {
1150eaf192dSyasuoka 	FIND_ATTRIBUTE_BEGIN(const,) {
1160eaf192dSyasuoka 		*length = MINIMUM(attr->length - 2, *length);
1170eaf192dSyasuoka 		memcpy(buf, attr->data, *length);
1180eaf192dSyasuoka 		return (0);
1190eaf192dSyasuoka 	} FIND_ATTRIBUTE_END;
1200eaf192dSyasuoka 
1210eaf192dSyasuoka 	return (-1);
1220eaf192dSyasuoka }
1230eaf192dSyasuoka 
1240eaf192dSyasuoka int
1250eaf192dSyasuoka radius_get_vs_raw_attr(const RADIUS_PACKET * packet, uint32_t vendor,
1260eaf192dSyasuoka     uint8_t vtype, void *buf, size_t * length)
1270eaf192dSyasuoka {
1280eaf192dSyasuoka 	FIND_VS_ATTRIBUTE_BEGIN(const,) {
1290eaf192dSyasuoka 		*length = MINIMUM(attr->vlength - 2, *length);
1300eaf192dSyasuoka 		memcpy(buf, attr->vdata, *length);
1310eaf192dSyasuoka 		return (0);
1320eaf192dSyasuoka 	} FIND_VS_ATTRIBUTE_END;
1330eaf192dSyasuoka 
1340eaf192dSyasuoka 	return (-1);
1350eaf192dSyasuoka }
1360eaf192dSyasuoka 
1370eaf192dSyasuoka int
1380eaf192dSyasuoka radius_get_raw_attr_cat(const RADIUS_PACKET * packet, uint8_t type, void *buf,
1390eaf192dSyasuoka     size_t * length)
1400eaf192dSyasuoka {
1410eaf192dSyasuoka 	size_t	 off = 0;
1420eaf192dSyasuoka 
1430eaf192dSyasuoka 	FIND_ATTRIBUTE_BEGIN(const,) {
1440eaf192dSyasuoka 		if (buf != NULL) {
1450eaf192dSyasuoka 			if (off + attr->length - 2 <= *length)
1460eaf192dSyasuoka 				memcpy((char *)buf + off, attr->data,
1470eaf192dSyasuoka 				    attr->length - 2);
1480eaf192dSyasuoka 			else
1490eaf192dSyasuoka 				return (-1);
1500eaf192dSyasuoka 		}
1510eaf192dSyasuoka 		off += attr->length - 2;
1520eaf192dSyasuoka 	} FIND_ATTRIBUTE_END;
1530eaf192dSyasuoka 
1540eaf192dSyasuoka 	*length = off;
1550eaf192dSyasuoka 
1560eaf192dSyasuoka 	return (0);
1570eaf192dSyasuoka }
1580eaf192dSyasuoka 
1590eaf192dSyasuoka int
1600eaf192dSyasuoka radius_get_vs_raw_attr_cat(const RADIUS_PACKET * packet, uint32_t vendor,
1610eaf192dSyasuoka     uint8_t vtype, void *buf, size_t * length)
1620eaf192dSyasuoka {
1630eaf192dSyasuoka 	size_t	 off = 0;
1640eaf192dSyasuoka 
1650eaf192dSyasuoka 	FIND_VS_ATTRIBUTE_BEGIN(const,) {
1660eaf192dSyasuoka 		if (buf != NULL) {
1670eaf192dSyasuoka 			if (off + attr->vlength - 2 <= *length)
1680eaf192dSyasuoka 				memcpy((char *)buf + off, attr->vdata,
1690eaf192dSyasuoka 				    attr->vlength - 2);
1700eaf192dSyasuoka 			else
1710eaf192dSyasuoka 				return (-1);
1720eaf192dSyasuoka 		}
1730eaf192dSyasuoka 		off += attr->vlength - 2;
1740eaf192dSyasuoka 	} FIND_VS_ATTRIBUTE_END;
1750eaf192dSyasuoka 
1760eaf192dSyasuoka 	*length = off;
1770eaf192dSyasuoka 
1780eaf192dSyasuoka 	return (0);
1790eaf192dSyasuoka }
1800eaf192dSyasuoka 
1810eaf192dSyasuoka int
1820eaf192dSyasuoka radius_put_raw_attr(RADIUS_PACKET * packet, uint8_t type, const void *buf,
1830eaf192dSyasuoka     size_t length)
1840eaf192dSyasuoka {
1850eaf192dSyasuoka 	RADIUS_ATTRIBUTE	*newattr;
1860eaf192dSyasuoka 
1870eaf192dSyasuoka 	if (length > 255 - 2)
1880eaf192dSyasuoka 		return (-1);
1890eaf192dSyasuoka 
1900eaf192dSyasuoka 	if (radius_ensure_add_capacity(packet, length + 2) != 0)
1910eaf192dSyasuoka 		return (-1);
1920eaf192dSyasuoka 
1930eaf192dSyasuoka 	newattr = ATTRS_END(packet->pdata);
1940eaf192dSyasuoka 	newattr->type = type;
1950eaf192dSyasuoka 	newattr->length = length + 2;
1960eaf192dSyasuoka 	memcpy(newattr->data, buf, length);
1970eaf192dSyasuoka 	packet->pdata->length = htons(radius_get_length(packet) + length + 2);
1980eaf192dSyasuoka 
1990eaf192dSyasuoka 	return (0);
2000eaf192dSyasuoka }
2010eaf192dSyasuoka 
2020eaf192dSyasuoka int
203*834c20a7Syasuoka radius_unshift_raw_attr(RADIUS_PACKET * packet, uint8_t type, const void *buf,
204*834c20a7Syasuoka     size_t length)
205*834c20a7Syasuoka {
206*834c20a7Syasuoka 	RADIUS_ATTRIBUTE	*newattr;
207*834c20a7Syasuoka 
208*834c20a7Syasuoka 	if (length > 255 - 2)
209*834c20a7Syasuoka 		return (-1);
210*834c20a7Syasuoka 
211*834c20a7Syasuoka 	if (radius_ensure_add_capacity(packet, length + 2) != 0)
212*834c20a7Syasuoka 		return (-1);
213*834c20a7Syasuoka 
214*834c20a7Syasuoka 	memmove(packet->pdata->attributes + length + 2,
215*834c20a7Syasuoka 	    packet->pdata->attributes,
216*834c20a7Syasuoka 	    radius_get_length(packet) - sizeof(RADIUS_PACKET_DATA));
217*834c20a7Syasuoka 
218*834c20a7Syasuoka 	newattr = ATTRS_BEGIN(packet->pdata);
219*834c20a7Syasuoka 	newattr->type = type;
220*834c20a7Syasuoka 	newattr->length = length + 2;
221*834c20a7Syasuoka 	memcpy(newattr->data, buf, length);
222*834c20a7Syasuoka 	packet->pdata->length = htons(radius_get_length(packet) + length + 2);
223*834c20a7Syasuoka 
224*834c20a7Syasuoka 	return (0);
225*834c20a7Syasuoka }
226*834c20a7Syasuoka 
227*834c20a7Syasuoka int
2280eaf192dSyasuoka radius_put_vs_raw_attr(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype,
2290eaf192dSyasuoka     const void *buf, size_t length)
2300eaf192dSyasuoka {
2310eaf192dSyasuoka 	RADIUS_ATTRIBUTE	*newattr;
2320eaf192dSyasuoka 
2330eaf192dSyasuoka 	if (length > 255 - 8)
2340eaf192dSyasuoka 		return (-1);
2350eaf192dSyasuoka 	if ((vendor & 0xff000000U) != 0)
2360eaf192dSyasuoka 		return (-1);
2370eaf192dSyasuoka 
2380eaf192dSyasuoka 	if (radius_ensure_add_capacity(packet, length + 8) != 0)
2390eaf192dSyasuoka 		return (-1);
2400eaf192dSyasuoka 
2410eaf192dSyasuoka 	newattr = ATTRS_END(packet->pdata);
2420eaf192dSyasuoka 	newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC;
2430eaf192dSyasuoka 	newattr->length = length + 8;
2440eaf192dSyasuoka 	newattr->vendor = htonl(vendor);
2450eaf192dSyasuoka 	newattr->vtype = vtype;
2460eaf192dSyasuoka 	newattr->vlength = length + 2;
2470eaf192dSyasuoka 	memcpy(newattr->vdata, buf, length);
2480eaf192dSyasuoka 	packet->pdata->length = htons(radius_get_length(packet) + length + 8);
2490eaf192dSyasuoka 
2500eaf192dSyasuoka 	return (0);
2510eaf192dSyasuoka }
2520eaf192dSyasuoka 
2530eaf192dSyasuoka int
2540eaf192dSyasuoka radius_put_raw_attr_cat(RADIUS_PACKET * packet, uint8_t type, const void *buf,
2550eaf192dSyasuoka     size_t length)
2560eaf192dSyasuoka {
2570eaf192dSyasuoka 	int	 off, len0;
2580eaf192dSyasuoka 
2590eaf192dSyasuoka 	off = 0;
2600eaf192dSyasuoka 	while (off < length) {
2610eaf192dSyasuoka 		len0 = MINIMUM(length - off, 255 - 2);
2620eaf192dSyasuoka 
2630eaf192dSyasuoka 		if (radius_put_raw_attr(packet, type, (const char *)buf + off,
2640eaf192dSyasuoka 		    len0) != 0)
2650eaf192dSyasuoka 			return (-1);
2660eaf192dSyasuoka 
2670eaf192dSyasuoka 		off += len0;
2680eaf192dSyasuoka 	}
2690eaf192dSyasuoka 
2700eaf192dSyasuoka 	return (0);
2710eaf192dSyasuoka }
2720eaf192dSyasuoka 
2730eaf192dSyasuoka int
2740eaf192dSyasuoka radius_put_vs_raw_attr_cat(RADIUS_PACKET * packet, uint32_t vendor,
2750eaf192dSyasuoka     uint8_t vtype, const void *buf, size_t length)
2760eaf192dSyasuoka {
2770eaf192dSyasuoka 	int	 off, len0;
2780eaf192dSyasuoka 
2790eaf192dSyasuoka 	off = 0;
2800eaf192dSyasuoka 	while (off < length) {
2810eaf192dSyasuoka 		len0 = MINIMUM(length - off, 255 - 8);
2820eaf192dSyasuoka 
2830eaf192dSyasuoka 		if (radius_put_vs_raw_attr(packet, vendor, vtype,
2840eaf192dSyasuoka 		    (const char *)buf + off, len0) != 0)
2850eaf192dSyasuoka 			return (-1);
2860eaf192dSyasuoka 
2870eaf192dSyasuoka 		off += len0;
2880eaf192dSyasuoka 	}
2890eaf192dSyasuoka 
2900eaf192dSyasuoka 	return (0);
2910eaf192dSyasuoka }
2920eaf192dSyasuoka 
2930eaf192dSyasuoka int
2940eaf192dSyasuoka radius_set_raw_attr(RADIUS_PACKET * packet,
2950eaf192dSyasuoka     uint8_t type, const void *buf, size_t length)
2960eaf192dSyasuoka {
2970eaf192dSyasuoka 	FIND_ATTRIBUTE_BEGIN(,) {
2980eaf192dSyasuoka 		if (length != attr->length - 2)
2990eaf192dSyasuoka 			return (-1);
3000eaf192dSyasuoka 		memcpy(attr->data, buf, length);
3010eaf192dSyasuoka 		return (0);
3020eaf192dSyasuoka 	} FIND_ATTRIBUTE_END;
3030eaf192dSyasuoka 
3040eaf192dSyasuoka 	return (-1);
3050eaf192dSyasuoka }
3060eaf192dSyasuoka 
3070eaf192dSyasuoka int
3080eaf192dSyasuoka radius_set_vs_raw_attr(RADIUS_PACKET * packet,
3090eaf192dSyasuoka     uint32_t vendor, uint8_t vtype, const void *buf, size_t length)
3100eaf192dSyasuoka {
3110eaf192dSyasuoka 	FIND_VS_ATTRIBUTE_BEGIN(,) {
3120eaf192dSyasuoka 		if (length != attr->vlength - 2)
3130eaf192dSyasuoka 			return (-1);
3140eaf192dSyasuoka 		memcpy(attr->vdata, buf, length);
3150eaf192dSyasuoka 		return (0);
3160eaf192dSyasuoka 	} FIND_VS_ATTRIBUTE_END;
3170eaf192dSyasuoka 
3180eaf192dSyasuoka 	return (-1);
3190eaf192dSyasuoka }
3200eaf192dSyasuoka 
3210eaf192dSyasuoka int
3220eaf192dSyasuoka radius_del_attr_all(RADIUS_PACKET * packet, uint8_t type)
3230eaf192dSyasuoka {
3240eaf192dSyasuoka 	FIND_ATTRIBUTE_BEGIN(, redo:) {
3250eaf192dSyasuoka 		RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
3260eaf192dSyasuoka 		packet->pdata->length =
3270eaf192dSyasuoka 		    htons(ntohs(packet->pdata->length) - attr->length);
3280eaf192dSyasuoka 		memmove(attr, next, ((char *)end) - ((char *)next));
3290eaf192dSyasuoka 		end = ATTRS_END(packet->pdata);
3300eaf192dSyasuoka 		goto redo;
3310eaf192dSyasuoka 	} FIND_ATTRIBUTE_END;
3320eaf192dSyasuoka 
3330eaf192dSyasuoka 	return (0);
3340eaf192dSyasuoka }
3350eaf192dSyasuoka 
3360eaf192dSyasuoka int
3370eaf192dSyasuoka radius_del_vs_attr_all(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
3380eaf192dSyasuoka {
3390eaf192dSyasuoka 	FIND_VS_ATTRIBUTE_BEGIN(, redo:) {
3400eaf192dSyasuoka 		RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
3410eaf192dSyasuoka 		packet->pdata->length =
3420eaf192dSyasuoka 		    htons(ntohs(packet->pdata->length) - attr->length);
3430eaf192dSyasuoka 		memmove(attr, next, ((char *)end) - ((char *)next));
3440eaf192dSyasuoka 		end = ATTRS_END(packet->pdata);
3450eaf192dSyasuoka 		goto redo;
3460eaf192dSyasuoka 	} FIND_VS_ATTRIBUTE_END;
3470eaf192dSyasuoka 
3480eaf192dSyasuoka 	return (0);
3490eaf192dSyasuoka }
3500eaf192dSyasuoka 
3510eaf192dSyasuoka bool
3520eaf192dSyasuoka radius_has_attr(const RADIUS_PACKET * packet, uint8_t type)
3530eaf192dSyasuoka {
3540eaf192dSyasuoka 	FIND_ATTRIBUTE_BEGIN(const,) {
3550eaf192dSyasuoka 		return (true);
3560eaf192dSyasuoka 	} FIND_VS_ATTRIBUTE_END;
3570eaf192dSyasuoka 
3580eaf192dSyasuoka 	return (false);
3590eaf192dSyasuoka }
3600eaf192dSyasuoka 
3610eaf192dSyasuoka bool
3620eaf192dSyasuoka radius_has_vs_attr(const RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
3630eaf192dSyasuoka {
3640eaf192dSyasuoka 	FIND_VS_ATTRIBUTE_BEGIN(const,) {
3650eaf192dSyasuoka 		return (true);
3660eaf192dSyasuoka 	} FIND_VS_ATTRIBUTE_END;
3670eaf192dSyasuoka 
3680eaf192dSyasuoka 	return (false);
3690eaf192dSyasuoka }
3700eaf192dSyasuoka 
3710eaf192dSyasuoka int
3720eaf192dSyasuoka radius_get_string_attr(const RADIUS_PACKET * packet, uint8_t type, char *str,
3730eaf192dSyasuoka     size_t len)
3740eaf192dSyasuoka {
3750eaf192dSyasuoka 	const void	*p;
3760eaf192dSyasuoka 	size_t		 origlen;
3770eaf192dSyasuoka 
3780eaf192dSyasuoka 	if (radius_get_raw_attr_ptr(packet, type, &p, &origlen) != 0)
3790eaf192dSyasuoka 		return (-1);
3800eaf192dSyasuoka 	if (memchr(p, 0, origlen) != NULL)
3810eaf192dSyasuoka 		return (-1);
3820eaf192dSyasuoka 	if (len >= 1) {
3830eaf192dSyasuoka 		len = MINIMUM(origlen, len - 1);
3840eaf192dSyasuoka 		memcpy(str, (const char *)p, len);
3850eaf192dSyasuoka 		str[len] = '\0';
3860eaf192dSyasuoka 	}
3870eaf192dSyasuoka 	return (0);
3880eaf192dSyasuoka }
3890eaf192dSyasuoka 
3900eaf192dSyasuoka int
3910eaf192dSyasuoka radius_get_vs_string_attr(const RADIUS_PACKET * packet,
3920eaf192dSyasuoka     uint32_t vendor, uint8_t vtype, char *str, size_t len)
3930eaf192dSyasuoka {
3940eaf192dSyasuoka 	const void *p;
3950eaf192dSyasuoka 	size_t origlen;
3960eaf192dSyasuoka 
3970eaf192dSyasuoka 	if (radius_get_vs_raw_attr_ptr(packet,
3980eaf192dSyasuoka 		vendor, vtype, &p, &origlen) != 0)
3990eaf192dSyasuoka 		return (-1);
4000eaf192dSyasuoka 	if (memchr(p, 0, origlen) != NULL)
4010eaf192dSyasuoka 		return (-1);
4020eaf192dSyasuoka 	if (len >= 1) {
4030eaf192dSyasuoka 		len = MINIMUM(origlen, len - 1);
4040eaf192dSyasuoka 		memcpy(str, (const char *)p, len);
4050eaf192dSyasuoka 		str[len] = '\0';
4060eaf192dSyasuoka 	}
4070eaf192dSyasuoka 
4080eaf192dSyasuoka 	return (0);
4090eaf192dSyasuoka }
4100eaf192dSyasuoka 
4110eaf192dSyasuoka int
4120eaf192dSyasuoka radius_put_string_attr(RADIUS_PACKET * packet, uint8_t type, const char *str)
4130eaf192dSyasuoka {
4140eaf192dSyasuoka 	return radius_put_raw_attr(packet, type, str, strlen(str));
4150eaf192dSyasuoka }
4160eaf192dSyasuoka 
4170eaf192dSyasuoka int
4180eaf192dSyasuoka radius_put_vs_string_attr(RADIUS_PACKET * packet,
4190eaf192dSyasuoka     uint32_t vendor, uint8_t vtype, const char *str)
4200eaf192dSyasuoka {
4210eaf192dSyasuoka 	return radius_put_vs_raw_attr(packet, vendor, vtype, str, strlen(str));
4220eaf192dSyasuoka }
4230eaf192dSyasuoka 
4240eaf192dSyasuoka 
4250eaf192dSyasuoka #define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ftname, tname, hton, ntoh) \
4260eaf192dSyasuoka int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet,		\
4270eaf192dSyasuoka 	uint8_t type, tname *val)					\
4280eaf192dSyasuoka {									\
4290eaf192dSyasuoka 	const void *p;							\
4300eaf192dSyasuoka 	tname nval;							\
4310eaf192dSyasuoka 	size_t len;							\
4320eaf192dSyasuoka 									\
4330eaf192dSyasuoka 	if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0)	\
4340eaf192dSyasuoka 		return (-1);						\
4350eaf192dSyasuoka 	if (len != sizeof(tname))					\
4360eaf192dSyasuoka 		return (-1);						\
4370eaf192dSyasuoka 	memcpy(&nval, p, sizeof(tname));				\
4380eaf192dSyasuoka 	*val = ntoh(nval);						\
4390eaf192dSyasuoka 	return (0);							\
4400eaf192dSyasuoka }									\
4410eaf192dSyasuoka 									\
4420eaf192dSyasuoka int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet,	\
4430eaf192dSyasuoka 	uint32_t vendor, uint8_t vtype, tname *val)			\
4440eaf192dSyasuoka {									\
4450eaf192dSyasuoka 	const void *p;							\
4460eaf192dSyasuoka 	tname nval;							\
4470eaf192dSyasuoka 	size_t len;							\
4480eaf192dSyasuoka 									\
4490eaf192dSyasuoka 	if (radius_get_vs_raw_attr_ptr(packet,				\
4500eaf192dSyasuoka 			vendor, vtype, &p, &len) != 0)			\
4510eaf192dSyasuoka 		return (-1);						\
4520eaf192dSyasuoka 	if (len != sizeof(tname))					\
4530eaf192dSyasuoka 		return (-1);						\
4540eaf192dSyasuoka 	memcpy(&nval, p, sizeof(tname));				\
4550eaf192dSyasuoka 	*val = ntoh(nval);						\
4560eaf192dSyasuoka 	return (0);							\
4570eaf192dSyasuoka }									\
4580eaf192dSyasuoka 									\
4590eaf192dSyasuoka int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
4600eaf192dSyasuoka 	uint8_t type, tname val)					\
4610eaf192dSyasuoka {									\
4620eaf192dSyasuoka 	tname nval;							\
4630eaf192dSyasuoka 									\
4640eaf192dSyasuoka 	nval = hton(val);						\
4650eaf192dSyasuoka 	return radius_put_raw_attr(packet, type, &nval, sizeof(tname));	\
4660eaf192dSyasuoka }									\
4670eaf192dSyasuoka 									\
4680eaf192dSyasuoka int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
4690eaf192dSyasuoka 	uint32_t vendor, uint8_t vtype, tname val)			\
4700eaf192dSyasuoka {									\
4710eaf192dSyasuoka 	tname nval;							\
4720eaf192dSyasuoka 									\
4730eaf192dSyasuoka 	nval = hton(val);						\
4740eaf192dSyasuoka 	return radius_put_vs_raw_attr(packet, vendor, vtype,		\
4750eaf192dSyasuoka 			&nval, sizeof(tname));				\
4760eaf192dSyasuoka }									\
4770eaf192dSyasuoka 									\
4780eaf192dSyasuoka int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
4790eaf192dSyasuoka 	uint8_t type, tname val)					\
4800eaf192dSyasuoka {									\
4810eaf192dSyasuoka 	tname nval;							\
4820eaf192dSyasuoka 									\
4830eaf192dSyasuoka 	nval = hton(val);						\
4840eaf192dSyasuoka 	return radius_set_raw_attr(packet, type, &nval, sizeof(tname));	\
4850eaf192dSyasuoka }									\
4860eaf192dSyasuoka 									\
4870eaf192dSyasuoka int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
4880eaf192dSyasuoka 	uint32_t vendor, uint8_t vtype, tname val)			\
4890eaf192dSyasuoka {									\
4900eaf192dSyasuoka 	tname nval;							\
4910eaf192dSyasuoka 									\
4920eaf192dSyasuoka 	nval = hton(val);						\
4930eaf192dSyasuoka 	return radius_set_vs_raw_attr(packet, vendor, vtype,		\
4940eaf192dSyasuoka 			&nval, sizeof(tname));				\
4950eaf192dSyasuoka }
4960eaf192dSyasuoka 
4970eaf192dSyasuoka #define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ftname, tname) \
4980eaf192dSyasuoka int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet,		\
4990eaf192dSyasuoka 	uint8_t type, tname *val)					\
5000eaf192dSyasuoka {									\
5010eaf192dSyasuoka 	const void	*p;						\
5020eaf192dSyasuoka 	size_t		 len;						\
5030eaf192dSyasuoka 									\
5040eaf192dSyasuoka 	if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0)	\
5050eaf192dSyasuoka 		return (-1);						\
5060eaf192dSyasuoka 	if (len != sizeof(tname))					\
5070eaf192dSyasuoka 		return (-1);						\
5080eaf192dSyasuoka 	memcpy(val, p, sizeof(tname));					\
5090eaf192dSyasuoka 	return (0);							\
5100eaf192dSyasuoka }									\
5110eaf192dSyasuoka 									\
5120eaf192dSyasuoka int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet,	\
5130eaf192dSyasuoka 	uint32_t vendor, uint8_t vtype, tname *val)			\
5140eaf192dSyasuoka {									\
5150eaf192dSyasuoka 	const void	*p;						\
5160eaf192dSyasuoka 	size_t		 len;						\
5170eaf192dSyasuoka 									\
5180eaf192dSyasuoka 	if (radius_get_vs_raw_attr_ptr(packet,				\
5190eaf192dSyasuoka 			vendor, vtype, &p, &len) != 0)			\
5200eaf192dSyasuoka 		return (-1);						\
5210eaf192dSyasuoka 	if (len != sizeof(tname))					\
5220eaf192dSyasuoka 		return (-1);						\
5230eaf192dSyasuoka 	memcpy(val, p, sizeof(tname));					\
5240eaf192dSyasuoka 	return (0);							\
5250eaf192dSyasuoka }									\
5260eaf192dSyasuoka 									\
5270eaf192dSyasuoka int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
5280eaf192dSyasuoka 	uint8_t type, const tname *val)					\
5290eaf192dSyasuoka {									\
5300eaf192dSyasuoka 	return radius_put_raw_attr(packet, type, val, sizeof(tname));	\
5310eaf192dSyasuoka }									\
5320eaf192dSyasuoka 									\
5330eaf192dSyasuoka int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
5340eaf192dSyasuoka 	uint32_t vendor, uint8_t vtype, const tname *val)		\
5350eaf192dSyasuoka {									\
5360eaf192dSyasuoka 	return radius_put_vs_raw_attr(packet, vendor, vtype,		\
5370eaf192dSyasuoka 			val, sizeof(tname));				\
5380eaf192dSyasuoka }									\
5390eaf192dSyasuoka 									\
5400eaf192dSyasuoka int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
5410eaf192dSyasuoka 	uint8_t type, const tname *val)					\
5420eaf192dSyasuoka {									\
5430eaf192dSyasuoka 	return radius_set_raw_attr(packet, type, val, sizeof(tname));	\
5440eaf192dSyasuoka }									\
5450eaf192dSyasuoka 									\
5460eaf192dSyasuoka int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
5470eaf192dSyasuoka 	uint32_t vendor, uint8_t vtype, const tname *val)		\
5480eaf192dSyasuoka {									\
5490eaf192dSyasuoka 	return radius_set_vs_raw_attr(packet, vendor, vtype,		\
5500eaf192dSyasuoka 			val, sizeof(tname));				\
5510eaf192dSyasuoka }
5520eaf192dSyasuoka 
5530eaf192dSyasuoka DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint16, uint16_t, htons, ntohs)
5540eaf192dSyasuoka DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint32, uint32_t, htonl, ntohl)
5550eaf192dSyasuoka DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint64, uint64_t, htobe64, betoh64)
5560eaf192dSyasuoka DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ipv4, struct in_addr,,)
5570eaf192dSyasuoka DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ipv6, struct in6_addr)
558