[BACK]Return to radius_attr.c CVS log [TXT][DIR] Up to [local] / src / lib / libradius

File: [local] / src / lib / libradius / radius_attr.c (download)

Revision 1.2, Sat Jul 8 08:53:26 2023 UTC (11 months ago) by yasuoka
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, HEAD
Changes since 1.1: +4 -5 lines

Tidy up #include lines.

/*	$OpenBSD: radius_attr.c,v 1.2 2023/07/08 08:53:26 yasuoka Exp $ */

/*-
 * Copyright (c) 2009 Internet Initiative Japan Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE"AUTHOR" AND CONTRIBUTORS AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <netinet/in.h>
#include <arpa/inet.h>

#include <endian.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#include "radius.h"

#include "radius_local.h"

#define FIND_ATTRIBUTE_BEGIN(constness, redolabel)		\
	constness RADIUS_ATTRIBUTE* attr;			\
	constness RADIUS_ATTRIBUTE* end;			\
								\
	attr = ATTRS_BEGIN(packet->pdata);			\
	end  = ATTRS_END(packet->pdata);			\
								\
	for (;; ATTRS_ADVANCE(attr))				\
	{							\
	redolabel						\
		if (attr >= end)				\
			break;					\
		if (attr->type != type)				\
			continue;				\
		{

#define FIND_ATTRIBUTE_END \
	} }

#define FIND_VS_ATTRIBUTE_BEGIN(constness, redolabel)		\
	constness RADIUS_ATTRIBUTE* attr;			\
	constness RADIUS_ATTRIBUTE* end;			\
								\
	attr = ATTRS_BEGIN(packet->pdata);			\
	end  = ATTRS_END(packet->pdata);			\
								\
	for (;; ATTRS_ADVANCE(attr))				\
	{							\
	redolabel						\
		if (attr >= end)				\
			break;					\
		if (attr->type != RADIUS_TYPE_VENDOR_SPECIFIC)	\
			continue;				\
		if (attr->vendor != htonl(vendor))		\
			continue;				\
		if (attr->vtype != vtype)			\
			continue;				\
		{

#define FIND_VS_ATTRIBUTE_END					\
	} }


int
radius_get_raw_attr_ptr(const RADIUS_PACKET * packet, uint8_t type,
    const void **ptr, size_t * length)
{
	FIND_ATTRIBUTE_BEGIN(const,) {
		*length = attr->length - 2;
		*ptr = attr->data;
		return (0);
	} FIND_ATTRIBUTE_END;

	return (-1);
}

int
radius_get_vs_raw_attr_ptr(const RADIUS_PACKET * packet, uint32_t vendor,
    uint8_t vtype, const void **ptr, size_t * length)
{
	FIND_VS_ATTRIBUTE_BEGIN(const,) {
		*length = attr->vlength - 2;
		*ptr = attr->vdata;
		return (0);
	} FIND_VS_ATTRIBUTE_END;

	return (-1);
}

int
radius_get_raw_attr(const RADIUS_PACKET * packet, uint8_t type, void *buf,
    size_t * length)
{
	FIND_ATTRIBUTE_BEGIN(const,) {
		*length = MINIMUM(attr->length - 2, *length);
		memcpy(buf, attr->data, *length);
		return (0);
	} FIND_ATTRIBUTE_END;

	return (-1);
}

int
radius_get_vs_raw_attr(const RADIUS_PACKET * packet, uint32_t vendor,
    uint8_t vtype, void *buf, size_t * length)
{
	FIND_VS_ATTRIBUTE_BEGIN(const,) {
		*length = MINIMUM(attr->vlength - 2, *length);
		memcpy(buf, attr->vdata, *length);
		return (0);
	} FIND_VS_ATTRIBUTE_END;

	return (-1);
}

int
radius_get_raw_attr_cat(const RADIUS_PACKET * packet, uint8_t type, void *buf,
    size_t * length)
{
	size_t	 off = 0;

	FIND_ATTRIBUTE_BEGIN(const,) {
		if (buf != NULL) {
			if (off + attr->length - 2 <= *length)
				memcpy((char *)buf + off, attr->data,
				    attr->length - 2);
			else
				return (-1);
		}
		off += attr->length - 2;
	} FIND_ATTRIBUTE_END;

	*length = off;

	return (0);
}

int
radius_get_vs_raw_attr_cat(const RADIUS_PACKET * packet, uint32_t vendor,
    uint8_t vtype, void *buf, size_t * length)
{
	size_t	 off = 0;

	FIND_VS_ATTRIBUTE_BEGIN(const,) {
		if (buf != NULL) {
			if (off + attr->vlength - 2 <= *length)
				memcpy((char *)buf + off, attr->vdata,
				    attr->vlength - 2);
			else
				return (-1);
		}
		off += attr->vlength - 2;
	} FIND_VS_ATTRIBUTE_END;

	*length = off;

	return (0);
}

int
radius_put_raw_attr(RADIUS_PACKET * packet, uint8_t type, const void *buf,
    size_t length)
{
	RADIUS_ATTRIBUTE	*newattr;

	if (length > 255 - 2)
		return (-1);

	if (radius_ensure_add_capacity(packet, length + 2) != 0)
		return (-1);

	newattr = ATTRS_END(packet->pdata);
	newattr->type = type;
	newattr->length = length + 2;
	memcpy(newattr->data, buf, length);
	packet->pdata->length = htons(radius_get_length(packet) + length + 2);

	return (0);
}

int
radius_put_vs_raw_attr(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype,
    const void *buf, size_t length)
{
	RADIUS_ATTRIBUTE	*newattr;

	if (length > 255 - 8)
		return (-1);
	if ((vendor & 0xff000000U) != 0)
		return (-1);

	if (radius_ensure_add_capacity(packet, length + 8) != 0)
		return (-1);

	newattr = ATTRS_END(packet->pdata);
	newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC;
	newattr->length = length + 8;
	newattr->vendor = htonl(vendor);
	newattr->vtype = vtype;
	newattr->vlength = length + 2;
	memcpy(newattr->vdata, buf, length);
	packet->pdata->length = htons(radius_get_length(packet) + length + 8);

	return (0);
}

int
radius_put_raw_attr_cat(RADIUS_PACKET * packet, uint8_t type, const void *buf,
    size_t length)
{
	int	 off, len0;

	off = 0;
	while (off < length) {
		len0 = MINIMUM(length - off, 255 - 2);

		if (radius_put_raw_attr(packet, type, (const char *)buf + off,
		    len0) != 0)
			return (-1);

		off += len0;
	}

	return (0);
}

int
radius_put_vs_raw_attr_cat(RADIUS_PACKET * packet, uint32_t vendor,
    uint8_t vtype, const void *buf, size_t length)
{
	int	 off, len0;

	off = 0;
	while (off < length) {
		len0 = MINIMUM(length - off, 255 - 8);

		if (radius_put_vs_raw_attr(packet, vendor, vtype,
		    (const char *)buf + off, len0) != 0)
			return (-1);

		off += len0;
	}

	return (0);
}

int
radius_set_raw_attr(RADIUS_PACKET * packet,
    uint8_t type, const void *buf, size_t length)
{
	FIND_ATTRIBUTE_BEGIN(,) {
		if (length != attr->length - 2)
			return (-1);
		memcpy(attr->data, buf, length);
		return (0);
	} FIND_ATTRIBUTE_END;

	return (-1);
}

int
radius_set_vs_raw_attr(RADIUS_PACKET * packet,
    uint32_t vendor, uint8_t vtype, const void *buf, size_t length)
{
	FIND_VS_ATTRIBUTE_BEGIN(,) {
		if (length != attr->vlength - 2)
			return (-1);
		memcpy(attr->vdata, buf, length);
		return (0);
	} FIND_VS_ATTRIBUTE_END;

	return (-1);
}

int
radius_del_attr_all(RADIUS_PACKET * packet, uint8_t type)
{
	FIND_ATTRIBUTE_BEGIN(, redo:) {
		RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
		packet->pdata->length =
		    htons(ntohs(packet->pdata->length) - attr->length);
		memmove(attr, next, ((char *)end) - ((char *)next));
		end = ATTRS_END(packet->pdata);
		goto redo;
	} FIND_ATTRIBUTE_END;

	return (0);
}

int
radius_del_vs_attr_all(RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
{
	FIND_VS_ATTRIBUTE_BEGIN(, redo:) {
		RADIUS_ATTRIBUTE *next = ATTRS_NEXT(attr);
		packet->pdata->length =
		    htons(ntohs(packet->pdata->length) - attr->length);
		memmove(attr, next, ((char *)end) - ((char *)next));
		end = ATTRS_END(packet->pdata);
		goto redo;
	} FIND_VS_ATTRIBUTE_END;

	return (0);
}

bool
radius_has_attr(const RADIUS_PACKET * packet, uint8_t type)
{
	FIND_ATTRIBUTE_BEGIN(const,) {
		return (true);
	} FIND_VS_ATTRIBUTE_END;

	return (false);
}

bool
radius_has_vs_attr(const RADIUS_PACKET * packet, uint32_t vendor, uint8_t vtype)
{
	FIND_VS_ATTRIBUTE_BEGIN(const,) {
		return (true);
	} FIND_VS_ATTRIBUTE_END;

	return (false);
}

int
radius_get_string_attr(const RADIUS_PACKET * packet, uint8_t type, char *str,
    size_t len)
{
	const void	*p;
	size_t		 origlen;

	if (radius_get_raw_attr_ptr(packet, type, &p, &origlen) != 0)
		return (-1);
	if (memchr(p, 0, origlen) != NULL)
		return (-1);
	if (len >= 1) {
		len = MINIMUM(origlen, len - 1);
		memcpy(str, (const char *)p, len);
		str[len] = '\0';
	}
	return (0);
}

int
radius_get_vs_string_attr(const RADIUS_PACKET * packet,
    uint32_t vendor, uint8_t vtype, char *str, size_t len)
{
	const void *p;
	size_t origlen;

	if (radius_get_vs_raw_attr_ptr(packet,
		vendor, vtype, &p, &origlen) != 0)
		return (-1);
	if (memchr(p, 0, origlen) != NULL)
		return (-1);
	if (len >= 1) {
		len = MINIMUM(origlen, len - 1);
		memcpy(str, (const char *)p, len);
		str[len] = '\0';
	}

	return (0);
}

int
radius_put_string_attr(RADIUS_PACKET * packet, uint8_t type, const char *str)
{
	return radius_put_raw_attr(packet, type, str, strlen(str));
}

int
radius_put_vs_string_attr(RADIUS_PACKET * packet,
    uint32_t vendor, uint8_t vtype, const char *str)
{
	return radius_put_vs_raw_attr(packet, vendor, vtype, str, strlen(str));
}


#define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ftname, tname, hton, ntoh) \
int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet,		\
	uint8_t type, tname *val)					\
{									\
	const void *p;							\
	tname nval;							\
	size_t len;							\
									\
	if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0)	\
		return (-1);						\
	if (len != sizeof(tname))					\
		return (-1);						\
	memcpy(&nval, p, sizeof(tname));				\
	*val = ntoh(nval);						\
	return (0);							\
}									\
									\
int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet,	\
	uint32_t vendor, uint8_t vtype, tname *val)			\
{									\
	const void *p;							\
	tname nval;							\
	size_t len;							\
									\
	if (radius_get_vs_raw_attr_ptr(packet,				\
			vendor, vtype, &p, &len) != 0)			\
		return (-1);						\
	if (len != sizeof(tname))					\
		return (-1);						\
	memcpy(&nval, p, sizeof(tname));				\
	*val = ntoh(nval);						\
	return (0);							\
}									\
									\
int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
	uint8_t type, tname val)					\
{									\
	tname nval;							\
									\
	nval = hton(val);						\
	return radius_put_raw_attr(packet, type, &nval, sizeof(tname));	\
}									\
									\
int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
	uint32_t vendor, uint8_t vtype, tname val)			\
{									\
	tname nval;							\
									\
	nval = hton(val);						\
	return radius_put_vs_raw_attr(packet, vendor, vtype,		\
			&nval, sizeof(tname));				\
}									\
									\
int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
	uint8_t type, tname val)					\
{									\
	tname nval;							\
									\
	nval = hton(val);						\
	return radius_set_raw_attr(packet, type, &nval, sizeof(tname));	\
}									\
									\
int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
	uint32_t vendor, uint8_t vtype, tname val)			\
{									\
	tname nval;							\
									\
	nval = hton(val);						\
	return radius_set_vs_raw_attr(packet, vendor, vtype,		\
			&nval, sizeof(tname));				\
}

#define DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ftname, tname) \
int radius_get_ ## ftname ## _attr(const RADIUS_PACKET *packet,		\
	uint8_t type, tname *val)					\
{									\
	const void	*p;						\
	size_t		 len;						\
									\
	if (radius_get_raw_attr_ptr(packet, type, &p, &len) != 0)	\
		return (-1);						\
	if (len != sizeof(tname))					\
		return (-1);						\
	memcpy(val, p, sizeof(tname));					\
	return (0);							\
}									\
									\
int radius_get_vs_ ## ftname ## _attr(const RADIUS_PACKET *packet,	\
	uint32_t vendor, uint8_t vtype, tname *val)			\
{									\
	const void	*p;						\
	size_t		 len;						\
									\
	if (radius_get_vs_raw_attr_ptr(packet,				\
			vendor, vtype, &p, &len) != 0)			\
		return (-1);						\
	if (len != sizeof(tname))					\
		return (-1);						\
	memcpy(val, p, sizeof(tname));					\
	return (0);							\
}									\
									\
int radius_put_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
	uint8_t type, const tname *val)					\
{									\
	return radius_put_raw_attr(packet, type, val, sizeof(tname));	\
}									\
									\
int radius_put_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
	uint32_t vendor, uint8_t vtype, const tname *val)		\
{									\
	return radius_put_vs_raw_attr(packet, vendor, vtype,		\
			val, sizeof(tname));				\
}									\
									\
int radius_set_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
	uint8_t type, const tname *val)					\
{									\
	return radius_set_raw_attr(packet, type, val, sizeof(tname));	\
}									\
									\
int radius_set_vs_ ## ftname ## _attr(RADIUS_PACKET *packet,		\
	uint32_t vendor, uint8_t vtype, const tname *val)		\
{									\
	return radius_set_vs_raw_attr(packet, vendor, vtype,		\
			val, sizeof(tname));				\
}

DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint16, uint16_t, htons, ntohs)
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint32, uint32_t, htonl, ntohl)
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(uint64, uint64_t, htobe64, betoh64)
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYVAL(ipv4, struct in_addr,,)
DEFINE_TYPED_ATTRIBUTE_ACCESSOR_BYPTR(ipv6, struct in6_addr)