xref: /openbsd/lib/libradius/radius.c (revision 9c3f005c)
1*9c3f005cSyasuoka /*	$OpenBSD: radius.c,v 1.6 2024/08/14 04:50:31 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 <sys/socket.h>
300eaf192dSyasuoka #include <sys/uio.h>
317426d5d9Syasuoka #include <arpa/inet.h>
327426d5d9Syasuoka 
337426d5d9Syasuoka #include <stdint.h>
340eaf192dSyasuoka #include <stdio.h>
350eaf192dSyasuoka #include <stdlib.h>
360eaf192dSyasuoka #include <string.h>
370eaf192dSyasuoka 
380eaf192dSyasuoka #include <openssl/md5.h>
390eaf192dSyasuoka 
400eaf192dSyasuoka #include "radius.h"
410eaf192dSyasuoka 
420eaf192dSyasuoka #include "radius_local.h"
430eaf192dSyasuoka 
440eaf192dSyasuoka static uint8_t radius_id_counter = 0;
450eaf192dSyasuoka 
460eaf192dSyasuoka static int
radius_check_packet_data(const RADIUS_PACKET_DATA * pdata,size_t length)474551b161Syasuoka radius_check_packet_data(const RADIUS_PACKET_DATA * pdata, size_t length)
480eaf192dSyasuoka {
490eaf192dSyasuoka 	const RADIUS_ATTRIBUTE	*attr;
500eaf192dSyasuoka 	const RADIUS_ATTRIBUTE	*end;
510eaf192dSyasuoka 
520eaf192dSyasuoka 	if (length < sizeof(RADIUS_PACKET_DATA))
530eaf192dSyasuoka 		return (-1);
540eaf192dSyasuoka 	if (length > 0xffff)
550eaf192dSyasuoka 		return (-1);
560eaf192dSyasuoka 	if (length != (size_t) ntohs(pdata->length))
570eaf192dSyasuoka 		return (-1);
580eaf192dSyasuoka 
590eaf192dSyasuoka 	attr = ATTRS_BEGIN(pdata);
600eaf192dSyasuoka 	end = ATTRS_END(pdata);
610eaf192dSyasuoka 	for (; attr < end; ATTRS_ADVANCE(attr)) {
620eaf192dSyasuoka 		if (attr->length < 2)
630eaf192dSyasuoka 			return (-1);
640eaf192dSyasuoka 		if (attr->type == RADIUS_TYPE_VENDOR_SPECIFIC) {
650eaf192dSyasuoka 			if (attr->length < 8)
660eaf192dSyasuoka 				return (-1);
670eaf192dSyasuoka 			if ((attr->vendor & htonl(0xff000000U)) != 0)
680eaf192dSyasuoka 				return (-1);
690eaf192dSyasuoka 			if (attr->length != attr->vlength + 6)
700eaf192dSyasuoka 				return (-1);
710eaf192dSyasuoka 		}
720eaf192dSyasuoka 	}
730eaf192dSyasuoka 
740eaf192dSyasuoka 	if (attr != end)
750eaf192dSyasuoka 		return (-1);
760eaf192dSyasuoka 
770eaf192dSyasuoka 	return (0);
780eaf192dSyasuoka }
790eaf192dSyasuoka 
800eaf192dSyasuoka int
radius_ensure_add_capacity(RADIUS_PACKET * packet,size_t capacity)810eaf192dSyasuoka radius_ensure_add_capacity(RADIUS_PACKET * packet, size_t capacity)
820eaf192dSyasuoka {
830eaf192dSyasuoka 	size_t	 newsize;
840eaf192dSyasuoka 	void	*newptr;
850eaf192dSyasuoka 
860eaf192dSyasuoka 	/*
870eaf192dSyasuoka 	 * The maximum size is 64KB.
880eaf192dSyasuoka 	 * We use little bit smaller value for our safety(?).
890eaf192dSyasuoka 	 */
900eaf192dSyasuoka 	if (ntohs(packet->pdata->length) + capacity > 0xfe00)
910eaf192dSyasuoka 		return (-1);
920eaf192dSyasuoka 
930eaf192dSyasuoka 	if (ntohs(packet->pdata->length) + capacity > packet->capacity) {
940eaf192dSyasuoka 		newsize = ntohs(packet->pdata->length) + capacity +
950eaf192dSyasuoka 		    RADIUS_PACKET_CAPACITY_INCREMENT;
960eaf192dSyasuoka 		newptr = realloc(packet->pdata, newsize);
970eaf192dSyasuoka 		if (newptr == NULL)
980eaf192dSyasuoka 			return (-1);
990eaf192dSyasuoka 		packet->capacity = newsize;
1000eaf192dSyasuoka 		packet->pdata = (RADIUS_PACKET_DATA *)newptr;
1010eaf192dSyasuoka 	}
1020eaf192dSyasuoka 	return (0);
1030eaf192dSyasuoka }
1040eaf192dSyasuoka 
1050eaf192dSyasuoka RADIUS_PACKET *
radius_new_request_packet(uint8_t code)1060eaf192dSyasuoka radius_new_request_packet(uint8_t code)
1070eaf192dSyasuoka {
1080eaf192dSyasuoka 	RADIUS_PACKET	*packet;
1090eaf192dSyasuoka 
110285f54cdSderaadt 	packet = malloc(sizeof(RADIUS_PACKET));
1110eaf192dSyasuoka 	if (packet == NULL)
1120eaf192dSyasuoka 		return (NULL);
113285f54cdSderaadt 	packet->pdata = malloc(RADIUS_PACKET_CAPACITY_INITIAL);
1140eaf192dSyasuoka 	if (packet->pdata == NULL) {
1150eaf192dSyasuoka 		free(packet);
1160eaf192dSyasuoka 		return (NULL);
1170eaf192dSyasuoka 	}
1180eaf192dSyasuoka 	packet->capacity = RADIUS_PACKET_CAPACITY_INITIAL;
1190eaf192dSyasuoka 	packet->request = NULL;
1200eaf192dSyasuoka 	packet->pdata->code = code;
1210eaf192dSyasuoka 	packet->pdata->id = radius_id_counter++;
1220eaf192dSyasuoka 	packet->pdata->length = htons(sizeof(RADIUS_PACKET_DATA));
1230eaf192dSyasuoka 	arc4random_buf(packet->pdata->authenticator,
1240eaf192dSyasuoka 	    sizeof(packet->pdata->authenticator));
1250eaf192dSyasuoka 
1260eaf192dSyasuoka 	return (packet);
1270eaf192dSyasuoka }
1280eaf192dSyasuoka 
1290eaf192dSyasuoka RADIUS_PACKET *
radius_new_response_packet(uint8_t code,const RADIUS_PACKET * request)1300eaf192dSyasuoka radius_new_response_packet(uint8_t code, const RADIUS_PACKET * request)
1310eaf192dSyasuoka {
1320eaf192dSyasuoka 	RADIUS_PACKET	*packet;
1330eaf192dSyasuoka 
1340eaf192dSyasuoka 	packet = radius_new_request_packet(code);
1350eaf192dSyasuoka 	if (packet == NULL)
1360eaf192dSyasuoka 		return (NULL);
1370eaf192dSyasuoka 	packet->request = request;
1380eaf192dSyasuoka 	packet->pdata->id = request->pdata->id;
1390eaf192dSyasuoka 
1400eaf192dSyasuoka 	return (packet);
1410eaf192dSyasuoka }
1420eaf192dSyasuoka 
1430eaf192dSyasuoka RADIUS_PACKET *
radius_convert_packet(const void * pdata,size_t length)1440eaf192dSyasuoka radius_convert_packet(const void *pdata, size_t length)
1450eaf192dSyasuoka {
1460eaf192dSyasuoka 	RADIUS_PACKET *packet;
1470eaf192dSyasuoka 
1480eaf192dSyasuoka 	if (radius_check_packet_data((const RADIUS_PACKET_DATA *)pdata,
1490eaf192dSyasuoka 	    length) != 0)
1500eaf192dSyasuoka 		return (NULL);
151285f54cdSderaadt 	packet = malloc(sizeof(RADIUS_PACKET));
1520eaf192dSyasuoka 	if (packet == NULL)
1530eaf192dSyasuoka 		return (NULL);
154285f54cdSderaadt 	packet->pdata = malloc(length);
1550eaf192dSyasuoka 	packet->capacity = length;
1560eaf192dSyasuoka 	packet->request = NULL;
1570eaf192dSyasuoka 	if (packet->pdata == NULL) {
1580eaf192dSyasuoka 		free(packet);
1590eaf192dSyasuoka 		return (NULL);
1600eaf192dSyasuoka 	}
1610eaf192dSyasuoka 	memcpy(packet->pdata, pdata, length);
1620eaf192dSyasuoka 
1630eaf192dSyasuoka 	return (packet);
1640eaf192dSyasuoka }
1650eaf192dSyasuoka 
1660eaf192dSyasuoka int
radius_delete_packet(RADIUS_PACKET * packet)1670eaf192dSyasuoka radius_delete_packet(RADIUS_PACKET * packet)
1680eaf192dSyasuoka {
1690eaf192dSyasuoka 	free(packet->pdata);
1700eaf192dSyasuoka 	free(packet);
1710eaf192dSyasuoka 	return (0);
1720eaf192dSyasuoka }
1730eaf192dSyasuoka 
1740eaf192dSyasuoka uint8_t
radius_get_code(const RADIUS_PACKET * packet)1750eaf192dSyasuoka radius_get_code(const RADIUS_PACKET * packet)
1760eaf192dSyasuoka {
1770eaf192dSyasuoka 	return (packet->pdata->code);
1780eaf192dSyasuoka }
1790eaf192dSyasuoka 
1800eaf192dSyasuoka uint8_t
radius_get_id(const RADIUS_PACKET * packet)1810eaf192dSyasuoka radius_get_id(const RADIUS_PACKET * packet)
1820eaf192dSyasuoka {
1830eaf192dSyasuoka 	return (packet->pdata->id);
1840eaf192dSyasuoka }
1850eaf192dSyasuoka 
1860eaf192dSyasuoka void
radius_update_id(RADIUS_PACKET * packet)1870eaf192dSyasuoka radius_update_id(RADIUS_PACKET * packet)
1880eaf192dSyasuoka {
1890eaf192dSyasuoka 	packet->pdata->id = radius_id_counter++;
1900eaf192dSyasuoka }
1910eaf192dSyasuoka 
1920eaf192dSyasuoka void
radius_set_id(RADIUS_PACKET * packet,uint8_t id)1930eaf192dSyasuoka radius_set_id(RADIUS_PACKET * packet, uint8_t id)
1940eaf192dSyasuoka {
1950eaf192dSyasuoka 	packet->pdata->id = id;
1960eaf192dSyasuoka }
1970eaf192dSyasuoka 
1980eaf192dSyasuoka void
radius_get_authenticator(const RADIUS_PACKET * packet,void * authenticator)1990eaf192dSyasuoka radius_get_authenticator(const RADIUS_PACKET * packet, void *authenticator)
2000eaf192dSyasuoka {
2010eaf192dSyasuoka 	memcpy(authenticator, packet->pdata->authenticator, 16);
2020eaf192dSyasuoka }
2030eaf192dSyasuoka 
2040eaf192dSyasuoka uint8_t *
radius_get_authenticator_retval(const RADIUS_PACKET * packet)2050eaf192dSyasuoka radius_get_authenticator_retval(const RADIUS_PACKET * packet)
2060eaf192dSyasuoka {
2070eaf192dSyasuoka 	return (packet->pdata->authenticator);
2080eaf192dSyasuoka }
2090eaf192dSyasuoka 
2100eaf192dSyasuoka uint8_t *
radius_get_request_authenticator_retval(const RADIUS_PACKET * packet)2110eaf192dSyasuoka radius_get_request_authenticator_retval(const RADIUS_PACKET * packet)
2120eaf192dSyasuoka {
2130eaf192dSyasuoka 	if (packet->request == NULL)
2140eaf192dSyasuoka 		return (packet->pdata->authenticator);
2150eaf192dSyasuoka 	else
2160eaf192dSyasuoka 		return (packet->request->pdata->authenticator);
2170eaf192dSyasuoka }
2180eaf192dSyasuoka 
2190eaf192dSyasuoka void
radius_set_request_packet(RADIUS_PACKET * packet,const RADIUS_PACKET * request)2200eaf192dSyasuoka radius_set_request_packet(RADIUS_PACKET * packet,
2210eaf192dSyasuoka     const RADIUS_PACKET * request)
2220eaf192dSyasuoka {
2230eaf192dSyasuoka 	packet->request = request;
2240eaf192dSyasuoka }
2250eaf192dSyasuoka 
2260eaf192dSyasuoka const RADIUS_PACKET *
radius_get_request_packet(const RADIUS_PACKET * packet)2270eaf192dSyasuoka radius_get_request_packet(const RADIUS_PACKET * packet)
2280eaf192dSyasuoka {
2290eaf192dSyasuoka 	return (packet->request);
2300eaf192dSyasuoka }
2310eaf192dSyasuoka 
2320eaf192dSyasuoka static void
radius_calc_authenticator(uint8_t * authenticator_dst,const RADIUS_PACKET * packet,const uint8_t * authenticator_src,const char * secret)2330eaf192dSyasuoka radius_calc_authenticator(uint8_t * authenticator_dst,
2340eaf192dSyasuoka     const RADIUS_PACKET * packet, const uint8_t * authenticator_src,
2350eaf192dSyasuoka     const char *secret)
2360eaf192dSyasuoka {
2370eaf192dSyasuoka 	MD5_CTX	 ctx;
2380eaf192dSyasuoka 
2390eaf192dSyasuoka 	MD5_Init(&ctx);
2400eaf192dSyasuoka 	MD5_Update(&ctx, (unsigned char *)packet->pdata, 4);
2410eaf192dSyasuoka 	MD5_Update(&ctx, (unsigned char *)authenticator_src, 16);
2420eaf192dSyasuoka 	MD5_Update(&ctx,
2430eaf192dSyasuoka 	    (unsigned char *)packet->pdata->attributes,
2440eaf192dSyasuoka 	    radius_get_length(packet) - 20);
2450eaf192dSyasuoka 	MD5_Update(&ctx, (unsigned char *)secret, strlen(secret));
2460eaf192dSyasuoka 	MD5_Final((unsigned char *)authenticator_dst, &ctx);
2470eaf192dSyasuoka }
2480eaf192dSyasuoka 
2490eaf192dSyasuoka static void
radius_calc_response_authenticator(uint8_t * authenticator_dst,const RADIUS_PACKET * packet,const char * secret)2500eaf192dSyasuoka radius_calc_response_authenticator(uint8_t * authenticator_dst,
2510eaf192dSyasuoka     const RADIUS_PACKET * packet, const char *secret)
2520eaf192dSyasuoka {
2530eaf192dSyasuoka 	radius_calc_authenticator(authenticator_dst,
2540eaf192dSyasuoka 	    packet, packet->request->pdata->authenticator, secret);
2550eaf192dSyasuoka }
2560eaf192dSyasuoka 
2570eaf192dSyasuoka int
radius_check_response_authenticator(const RADIUS_PACKET * packet,const char * secret)2580eaf192dSyasuoka radius_check_response_authenticator(const RADIUS_PACKET * packet,
2590eaf192dSyasuoka     const char *secret)
2600eaf192dSyasuoka {
2610eaf192dSyasuoka 	uint8_t authenticator[16];
2620eaf192dSyasuoka 
2630eaf192dSyasuoka 	radius_calc_response_authenticator(authenticator, packet, secret);
264*9c3f005cSyasuoka 	return (timingsafe_bcmp(authenticator, packet->pdata->authenticator,
2659c0ae8ffSyasuoka 	    16));
2660eaf192dSyasuoka }
2670eaf192dSyasuoka 
2680eaf192dSyasuoka void
radius_set_response_authenticator(RADIUS_PACKET * packet,const char * secret)2690eaf192dSyasuoka radius_set_response_authenticator(RADIUS_PACKET * packet,
2700eaf192dSyasuoka     const char *secret)
2710eaf192dSyasuoka {
2720eaf192dSyasuoka 	radius_calc_response_authenticator(packet->pdata->authenticator,
2730eaf192dSyasuoka 	    packet, secret);
2740eaf192dSyasuoka }
2750eaf192dSyasuoka 
2760eaf192dSyasuoka static void
radius_calc_accounting_request_authenticator(uint8_t * authenticator_dst,const RADIUS_PACKET * packet,const char * secret)2770eaf192dSyasuoka radius_calc_accounting_request_authenticator(uint8_t * authenticator_dst,
2780eaf192dSyasuoka     const RADIUS_PACKET * packet, const char *secret)
2790eaf192dSyasuoka {
2800eaf192dSyasuoka 	uint8_t	 zero[16];
2810eaf192dSyasuoka 
2820eaf192dSyasuoka 	memset(zero, 0, sizeof(zero));
2830eaf192dSyasuoka 	radius_calc_authenticator(authenticator_dst,
2840eaf192dSyasuoka 	    packet, zero, secret);
2850eaf192dSyasuoka }
2860eaf192dSyasuoka 
2870eaf192dSyasuoka void
radius_set_accounting_request_authenticator(RADIUS_PACKET * packet,const char * secret)2880eaf192dSyasuoka radius_set_accounting_request_authenticator(RADIUS_PACKET * packet,
2890eaf192dSyasuoka     const char *secret)
2900eaf192dSyasuoka {
2910eaf192dSyasuoka 	radius_calc_accounting_request_authenticator(
2920eaf192dSyasuoka 	    packet->pdata->authenticator, packet, secret);
2930eaf192dSyasuoka }
2940eaf192dSyasuoka 
2950eaf192dSyasuoka int
radius_check_accounting_request_authenticator(const RADIUS_PACKET * packet,const char * secret)2960eaf192dSyasuoka radius_check_accounting_request_authenticator(const RADIUS_PACKET * packet,
2970eaf192dSyasuoka     const char *secret)
2980eaf192dSyasuoka {
2990eaf192dSyasuoka 	uint8_t authenticator[16];
3000eaf192dSyasuoka 
3010eaf192dSyasuoka 	radius_calc_accounting_request_authenticator(authenticator, packet,
3020eaf192dSyasuoka 	    secret);
303*9c3f005cSyasuoka 	return (timingsafe_bcmp(authenticator, packet->pdata->authenticator,
3049c0ae8ffSyasuoka 	    16));
3050eaf192dSyasuoka }
3060eaf192dSyasuoka 
3070eaf192dSyasuoka 
3080eaf192dSyasuoka uint16_t
radius_get_length(const RADIUS_PACKET * packet)3090eaf192dSyasuoka radius_get_length(const RADIUS_PACKET * packet)
3100eaf192dSyasuoka {
3110eaf192dSyasuoka 	return (ntohs(packet->pdata->length));
3120eaf192dSyasuoka }
3130eaf192dSyasuoka 
3140eaf192dSyasuoka 
3150eaf192dSyasuoka const void *
radius_get_data(const RADIUS_PACKET * packet)3160eaf192dSyasuoka radius_get_data(const RADIUS_PACKET * packet)
3170eaf192dSyasuoka {
3180eaf192dSyasuoka 	return (packet->pdata);
3190eaf192dSyasuoka }
3200eaf192dSyasuoka 
3210eaf192dSyasuoka RADIUS_PACKET *
radius_recvfrom(int s,int flags,struct sockaddr * sa,socklen_t * slen)3220eaf192dSyasuoka radius_recvfrom(int s, int flags, struct sockaddr * sa, socklen_t * slen)
3230eaf192dSyasuoka {
3240eaf192dSyasuoka 	char	 buf[0x10000];
3250eaf192dSyasuoka 	ssize_t	 n;
3260eaf192dSyasuoka 
3270eaf192dSyasuoka 	n = recvfrom(s, buf, sizeof(buf), flags, sa, slen);
3280eaf192dSyasuoka 	if (n <= 0)
3290eaf192dSyasuoka 		return (NULL);
3300eaf192dSyasuoka 
3310eaf192dSyasuoka 	return (radius_convert_packet(buf, (size_t) n));
3320eaf192dSyasuoka }
3330eaf192dSyasuoka 
3340eaf192dSyasuoka int
radius_sendto(int s,const RADIUS_PACKET * packet,int flags,const struct sockaddr * sa,socklen_t slen)3350eaf192dSyasuoka radius_sendto(int s, const RADIUS_PACKET * packet,
3360eaf192dSyasuoka     int flags, const struct sockaddr * sa, socklen_t slen)
3370eaf192dSyasuoka {
3380eaf192dSyasuoka 	ssize_t	 n;
3390eaf192dSyasuoka 
3400eaf192dSyasuoka 	n = sendto(s, packet->pdata, radius_get_length(packet), flags, sa,
3410eaf192dSyasuoka 	    slen);
3420eaf192dSyasuoka 	if (n != radius_get_length(packet))
3430eaf192dSyasuoka 		return (-1);
3440eaf192dSyasuoka 
3450eaf192dSyasuoka 	return (0);
3460eaf192dSyasuoka }
3470eaf192dSyasuoka 
3480eaf192dSyasuoka RADIUS_PACKET *
radius_recv(int s,int flags)3490eaf192dSyasuoka radius_recv(int s, int flags)
3500eaf192dSyasuoka {
3510eaf192dSyasuoka 	char	 buf[0x10000];
3520eaf192dSyasuoka 	ssize_t	 n;
3530eaf192dSyasuoka 
3540eaf192dSyasuoka 	n = recv(s, buf, sizeof(buf), flags);
3550eaf192dSyasuoka 	if (n <= 0)
3560eaf192dSyasuoka 		return (NULL);
3570eaf192dSyasuoka 
3580eaf192dSyasuoka 	return (radius_convert_packet(buf, (size_t) n));
3590eaf192dSyasuoka }
3600eaf192dSyasuoka 
3610eaf192dSyasuoka int
radius_send(int s,const RADIUS_PACKET * packet,int flags)3620eaf192dSyasuoka radius_send(int s, const RADIUS_PACKET * packet, int flags)
3630eaf192dSyasuoka {
3640eaf192dSyasuoka 	ssize_t	 n;
3650eaf192dSyasuoka 
3660eaf192dSyasuoka 	n = send(s, packet->pdata, radius_get_length(packet), flags);
3670eaf192dSyasuoka 	if (n != radius_get_length(packet))
3680eaf192dSyasuoka 		return (-1);
3690eaf192dSyasuoka 
3700eaf192dSyasuoka 	return (0);
3710eaf192dSyasuoka }
3720eaf192dSyasuoka 
3730eaf192dSyasuoka RADIUS_PACKET *
radius_recvmsg(int s,struct msghdr * msg,int flags)3740eaf192dSyasuoka radius_recvmsg(int s, struct msghdr * msg, int flags)
3750eaf192dSyasuoka {
3760eaf192dSyasuoka 	struct iovec	 iov;
3770eaf192dSyasuoka 	char		 buf[0x10000];
3780eaf192dSyasuoka 	ssize_t		 n;
3790eaf192dSyasuoka 
3800eaf192dSyasuoka 	if (msg->msg_iov != NULL || msg->msg_iovlen != 0)
3810eaf192dSyasuoka 		return (NULL);
3820eaf192dSyasuoka 
3830eaf192dSyasuoka 	iov.iov_base = buf;
3840eaf192dSyasuoka 	iov.iov_len = sizeof(buf);
3850eaf192dSyasuoka 	msg->msg_iov = &iov;
3860eaf192dSyasuoka 	msg->msg_iovlen = 1;
3870eaf192dSyasuoka 	n = recvmsg(s, msg, flags);
3880eaf192dSyasuoka 	msg->msg_iov = NULL;
3890eaf192dSyasuoka 	msg->msg_iovlen = 0;
3900eaf192dSyasuoka 	if (n <= 0)
3910eaf192dSyasuoka 		return (NULL);
3920eaf192dSyasuoka 
3930eaf192dSyasuoka 	return (radius_convert_packet(buf, (size_t) n));
3940eaf192dSyasuoka }
3950eaf192dSyasuoka 
3960eaf192dSyasuoka int
radius_sendmsg(int s,const RADIUS_PACKET * packet,const struct msghdr * msg,int flags)3970eaf192dSyasuoka radius_sendmsg(int s, const RADIUS_PACKET * packet,
3980eaf192dSyasuoka     const struct msghdr * msg, int flags)
3990eaf192dSyasuoka {
4000eaf192dSyasuoka 	struct msghdr	 msg0;
4010eaf192dSyasuoka 	struct iovec	 iov;
4020eaf192dSyasuoka 	ssize_t		 n;
4030eaf192dSyasuoka 
4040eaf192dSyasuoka 	if (msg->msg_iov != NULL || msg->msg_iovlen != 0)
4050eaf192dSyasuoka 		return (-1);
4060eaf192dSyasuoka 
4070eaf192dSyasuoka 	iov.iov_base = packet->pdata;
4080eaf192dSyasuoka 	iov.iov_len = radius_get_length(packet);
4090eaf192dSyasuoka 	msg0 = *msg;
4100eaf192dSyasuoka 	msg0.msg_iov = &iov;
4110eaf192dSyasuoka 	msg0.msg_iovlen = 1;
4120eaf192dSyasuoka 	n = sendmsg(s, &msg0, flags);
4130eaf192dSyasuoka 	if (n != radius_get_length(packet))
4140eaf192dSyasuoka 		return (-1);
4150eaf192dSyasuoka 
4160eaf192dSyasuoka 	return (0);
4170eaf192dSyasuoka }
418