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