summaryrefslogtreecommitdiff
path: root/usr.sbin/npppd/npppd/radius+.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/npppd/npppd/radius+.c')
-rw-r--r--usr.sbin/npppd/npppd/radius+.c763
1 files changed, 763 insertions, 0 deletions
diff --git a/usr.sbin/npppd/npppd/radius+.c b/usr.sbin/npppd/npppd/radius+.c
new file mode 100644
index 00000000000..35de1c72bb4
--- /dev/null
+++ b/usr.sbin/npppd/npppd/radius+.c
@@ -0,0 +1,763 @@
+/*-
+ * 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.
+ */
+/*
+ * radius+.cc :
+ * yet another RADIUS library
+ */
+#ifdef WITH_MPATROL
+#include <mpatrol.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <md5.h>
+#include "radius+.h"
+#include "radiusconst.h"
+
+#include "radius+_local.h"
+
+u_int8_t radius_id_counter = 0;
+
+static int radius_check_packet_data(const RADIUS_PACKET_DATA* pdata,
+ size_t length)
+{
+ const RADIUS_ATTRIBUTE* attr;
+ const RADIUS_ATTRIBUTE* end;
+
+ if(length < sizeof(RADIUS_PACKET_DATA))
+ return 1;
+ if(length > 0xffff)
+ return 1;
+ if(length != (size_t)ntohs(pdata->length))
+ return 1;
+
+ attr = ATTRS_BEGIN(pdata);
+ end = ATTRS_END(pdata);
+ for(; attr<end; ADVANCE(attr))
+ {
+ if(attr->length < 2)
+ return 1;
+ if(attr->type == RADIUS_TYPE_VENDOR_SPECIFIC)
+ {
+ if(attr->length < 8)
+ return 1;
+ if((attr->vendor & htonl(0xff000000U)) != 0)
+ return 1;
+ if(attr->length != attr->vlength + 6)
+ return 1;
+ }
+ }
+
+ if(attr != end)
+ return 1;
+
+ return 0;
+}
+
+static int radius_ensure_add_capacity(RADIUS_PACKET* packet, size_t capacity)
+{
+ size_t newsize;
+ void* newptr;
+
+ // 最大サイズは 64KB
+ // 安全のため(?)、少し小さい値をリミットにしている。
+ if(ntohs(packet->pdata->length) + capacity > 0xfe00)
+ return 1;
+
+ if(ntohs(packet->pdata->length) + capacity > packet->capacity)
+ {
+ newsize = ntohs(packet->pdata->length) + capacity +
+ RADIUS_PACKET_CAPACITY_INCREMENT;
+ newptr = realloc(packet->pdata, newsize);
+ if(newptr == NULL)
+ return 1;
+ packet->capacity = newsize;
+ packet->pdata = (RADIUS_PACKET_DATA*)newptr;
+ }
+
+ return 0;
+}
+
+RADIUS_PACKET* radius_new_request_packet(u_int8_t code)
+{
+ RADIUS_PACKET* packet;
+ unsigned int i;
+
+ packet = (RADIUS_PACKET*)malloc(sizeof(RADIUS_PACKET));
+ if(packet == NULL)
+ return NULL;
+ packet->pdata = (RADIUS_PACKET_DATA*)malloc(RADIUS_PACKET_CAPACITY_INITIAL);
+ if(packet->pdata == NULL)
+ {
+ free(packet);
+ return NULL;
+ }
+ packet->capacity = RADIUS_PACKET_CAPACITY_INITIAL;
+ packet->request = NULL;
+ packet->pdata->code = code;
+ packet->pdata->id = radius_id_counter++;
+ packet->pdata->length = htons(sizeof(RADIUS_PACKET_DATA));
+ for(i=0; i<countof(packet->pdata->authenticator); i++)
+ packet->pdata->authenticator[i] = rand()&0xff;
+
+ return packet;
+}
+
+RADIUS_PACKET* radius_new_response_packet(u_int8_t code,
+ const RADIUS_PACKET* request)
+{
+ RADIUS_PACKET* packet;
+
+ packet = radius_new_request_packet(code);
+ if(packet == NULL)
+ return NULL;
+ packet->request = request;
+ packet->pdata->id = request->pdata->id;
+
+ return packet;
+}
+
+RADIUS_PACKET* radius_convert_packet(const void* pdata, size_t length)
+{
+ RADIUS_PACKET* packet;
+
+ if(radius_check_packet_data((const RADIUS_PACKET_DATA*)pdata, length) != 0)
+ return NULL;
+ packet = (RADIUS_PACKET*)malloc(sizeof(RADIUS_PACKET));
+ if(packet == NULL)
+ return NULL;
+ packet->pdata = (RADIUS_PACKET_DATA*)malloc(length);
+ packet->capacity = length;
+ packet->request = NULL;
+ if(packet->pdata == NULL)
+ {
+ free(packet);
+ return NULL;
+ }
+ memcpy(packet->pdata, pdata, length);
+
+ return packet;
+}
+
+int radius_delete_packet(RADIUS_PACKET* packet)
+{
+ free(packet->pdata);
+ free(packet);
+ return 0;
+}
+
+u_int8_t radius_get_code(const RADIUS_PACKET* packet)
+{
+ return packet->pdata->code;
+}
+
+u_int8_t radius_get_id(const RADIUS_PACKET* packet)
+{
+ return packet->pdata->id;
+}
+
+void radius_get_authenticator(const RADIUS_PACKET* packet, char* authenticator)
+{
+ memcpy(authenticator, packet->pdata->authenticator, 16);
+}
+
+const char* radius_get_authenticator_retval(const RADIUS_PACKET* packet)
+{
+ return packet->pdata->authenticator;
+}
+
+void radius_set_request_packet(RADIUS_PACKET* packet,
+ const RADIUS_PACKET* request)
+{
+ packet->request = request;
+}
+
+int radius_check_response_authenticator(const RADIUS_PACKET* packet,
+ const char* secret)
+{
+ MD5_CTX ctx;
+ unsigned char authenticator0[16];
+
+ /* 呼び出し前に必ず radius_set_request_packet*/
+ if (packet->request == NULL)
+ return -1;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char*)packet->pdata, 4);
+ MD5Update(&ctx, (unsigned char*)packet->request->pdata->authenticator,
+ 16);
+ MD5Update(&ctx,
+ (unsigned char*)packet->pdata->attributes,
+ radius_get_length(packet) - 20);
+ MD5Update(&ctx, (unsigned char*)secret, strlen(secret));
+ MD5Final((unsigned char *)authenticator0, &ctx);
+
+ return memcmp(authenticator0, packet->pdata->authenticator, 16);
+}
+
+void radius_set_response_authenticator(RADIUS_PACKET* packet,
+ const char* secret)
+{
+ MD5_CTX ctx;
+
+ MD5Init(&ctx);
+ MD5Update(&ctx, (unsigned char*)packet->pdata, 4);
+ MD5Update(&ctx,
+ (unsigned char*)packet->request->pdata->authenticator, 16);
+ MD5Update(&ctx,
+ (unsigned char*)packet->pdata->attributes,
+ radius_get_length(packet) - 20);
+ MD5Update(&ctx, (unsigned char*)secret, strlen(secret));
+ MD5Final((unsigned char*)packet->pdata->authenticator ,&ctx);
+}
+
+u_int16_t radius_get_length(const RADIUS_PACKET* packet)
+{
+ return ntohs(packet->pdata->length);
+}
+
+
+const void* radius_get_data(const RADIUS_PACKET* packet)
+{
+ return packet->pdata;
+}
+
+int radius_get_raw_attr(const RADIUS_PACKET* packet, u_int8_t type,
+ void* buf, u_int8_t* length)
+{
+ const RADIUS_ATTRIBUTE* attr;
+ const RADIUS_ATTRIBUTE* end;
+
+ attr = ATTRS_BEGIN(packet->pdata);
+ end = ATTRS_END(packet->pdata);
+
+ for(; attr<end; ADVANCE(attr))
+ {
+ if(attr->type != type)
+ continue;
+ *length = attr->length - 2;
+ memcpy(buf, attr->data, attr->length - 2);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * To determine the length of the data, set the buf = NULL.
+ */
+int radius_get_raw_attr_all(const RADIUS_PACKET* packet, u_int8_t type,
+ caddr_t buf, int *length)
+{
+ int off;
+ const RADIUS_ATTRIBUTE* attr;
+ const RADIUS_ATTRIBUTE* end;
+
+ attr = ATTRS_BEGIN(packet->pdata);
+ end = ATTRS_END(packet->pdata);
+
+ for(off = 0; attr<end; ADVANCE(attr))
+ {
+ if(attr->type != type)
+ continue;
+ if (buf != NULL) {
+ if (off + attr->length - 2 <= *length)
+ memcpy(buf + off, attr->data, attr->length - 2);
+ else
+ return 1;
+ }
+ off += attr->length - 2;
+ }
+ *length = off;
+
+ return 0;
+}
+
+int radius_put_raw_attr(RADIUS_PACKET* packet, u_int8_t type,
+ const void* buf, u_int8_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_raw_attr_all(RADIUS_PACKET* packet, u_int8_t type,
+ caddr_t buf, int length)
+{
+ int off, len0;
+ RADIUS_ATTRIBUTE* newattr;
+
+ off = 0;
+ while (off < length) {
+ len0 = MIN(length - off, 255-2);
+
+ if(radius_ensure_add_capacity(packet, len0+2) != 0)
+ return 1;
+
+ newattr = ATTRS_END(packet->pdata);
+ newattr->type = type;
+ newattr->length = len0 + 2;
+ memcpy(newattr->data, buf, len0);
+ packet->pdata->length = htons(radius_get_length(packet) +
+ len0 + 2);
+
+ off += len0;
+ }
+
+ return 0;
+}
+
+int radius_get_vs_raw_attr(const RADIUS_PACKET* packet, u_int32_t vendor,
+ u_int8_t vtype, void* buf, u_int8_t* length)
+{
+ const RADIUS_ATTRIBUTE* attr;
+ const RADIUS_ATTRIBUTE* end;
+
+ attr = ATTRS_BEGIN(packet->pdata);
+ end = ATTRS_END(packet->pdata);
+
+ for(; attr<end; ADVANCE(attr))
+ {
+ if(attr->type != RADIUS_TYPE_VENDOR_SPECIFIC)
+ continue;
+ if(attr->vendor != htonl(vendor))
+ continue;
+ if(attr->vtype != vtype)
+ continue;
+
+ *length = attr->vlength - 2;
+ memcpy(buf, attr->vdata, attr->vlength - 2);
+ return 0;
+ }
+
+ return 1;
+}
+
+/*
+ * To determine the length of the data, set the buf = NULL.
+ */
+int radius_get_vs_raw_attr_all(const RADIUS_PACKET* packet, u_int32_t vendor,
+ u_int8_t vtype, caddr_t buf, int *length)
+{
+ int off;
+ const RADIUS_ATTRIBUTE* attr;
+ const RADIUS_ATTRIBUTE* end;
+
+ attr = ATTRS_BEGIN(packet->pdata);
+ end = ATTRS_END(packet->pdata);
+
+ off = 0;
+ for(; attr<end; ADVANCE(attr))
+ {
+ if(attr->type != RADIUS_TYPE_VENDOR_SPECIFIC)
+ continue;
+ if(attr->vendor != htonl(vendor))
+ continue;
+ if(attr->vtype != vtype)
+ continue;
+
+ if (buf != NULL) {
+ if (off + attr->vlength - 2 <= *length)
+ memcpy(off + buf, attr->vdata,
+ attr->vlength - 2);
+ else
+ return 1;
+ }
+ off += attr->vlength;
+ }
+ *length = off;
+
+ return 0;
+}
+
+int radius_get_vs_raw_attr_ptr(const RADIUS_PACKET* packet, u_int32_t vendor,
+ u_int8_t vtype, void** ptr, u_int8_t* length)
+{
+ const RADIUS_ATTRIBUTE* attr;
+ const RADIUS_ATTRIBUTE* end;
+
+ attr = ATTRS_BEGIN(packet->pdata);
+ end = ATTRS_END(packet->pdata);
+
+ for(; attr<end; ADVANCE(attr))
+ {
+ if(attr->type != RADIUS_TYPE_VENDOR_SPECIFIC)
+ continue;
+ if(attr->vendor != htonl(vendor))
+ continue;
+ if(attr->vtype != vtype)
+ continue;
+
+ *length = attr->vlength - 2;
+ *ptr = (void *)attr->vdata;
+ return 0;
+ }
+
+ return 1;
+}
+
+int radius_put_vs_raw_attr(RADIUS_PACKET* packet, u_int32_t vendor,
+ u_int8_t vtype, const void* buf, u_int8_t length)
+{
+ RADIUS_ATTRIBUTE* newattr;
+
+ if(length > 255-8)
+ 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_vs_raw_attr_all(RADIUS_PACKET* packet, u_int32_t vendor,
+ u_int8_t vtype, const void* buf, int length)
+{
+ int off, len0;
+ RADIUS_ATTRIBUTE* newattr;
+
+ off = 0;
+ while (off < length) {
+ len0 = MIN(length - off, 255-8);
+
+ if(radius_ensure_add_capacity(packet, len0+8) != 0)
+ return 1;
+
+ newattr = ATTRS_END(packet->pdata);
+ newattr->type = RADIUS_TYPE_VENDOR_SPECIFIC;
+ newattr->length = len0 + 8;
+ newattr->vendor = htonl(vendor);
+ newattr->vtype = vtype;
+ newattr->vlength = len0 + 2;
+ memcpy(newattr->vdata, buf, len0);
+ packet->pdata->length = htons(radius_get_length(packet) +
+ len0 + 8);
+
+ off += len0;
+ }
+
+ return 0;
+}
+
+int radius_get_uint32_attr(const RADIUS_PACKET* packet, u_int8_t type,
+ u_int32_t* val)
+{
+ u_int32_t nval;
+ u_int8_t len;
+
+ if(radius_get_raw_attr(packet, type, &nval, &len) != 0)
+ return 1;
+ if(len != sizeof(u_int32_t))
+ return 1;
+ *val = ntohl(nval);
+ return 0;
+}
+
+u_int32_t radius_get_uint32_attr_retval(const RADIUS_PACKET* packet,
+ u_int8_t type)
+{
+ u_int32_t nval;
+ u_int8_t len;
+
+ if(radius_get_raw_attr(packet, type, &nval, &len) != 0)
+ return 0xffffffff;
+ if(len != sizeof(u_int32_t))
+ return 0xffffffff;
+ return ntohl(nval);
+}
+
+int radius_put_uint32_attr(RADIUS_PACKET* packet, u_int8_t type, u_int32_t val)
+{
+ u_int32_t nval;
+
+ nval = htonl(val);
+ return radius_put_raw_attr(packet, type, &nval, sizeof(u_int32_t));
+}
+
+int radius_get_string_attr(const RADIUS_PACKET* packet, u_int8_t type,
+ char* str)
+{
+ u_int8_t len;
+
+ if(radius_get_raw_attr(packet, type, str, &len) != 0)
+ return 1;
+ str[len] = '\0';
+ return 0;
+}
+
+int radius_put_string_attr(RADIUS_PACKET* packet, u_int8_t type,
+ const char* str)
+{
+ return radius_put_raw_attr(packet, type, str, strlen(str));
+}
+
+int radius_get_vs_string_attr(const RADIUS_PACKET* packet, u_int32_t vendor,
+ u_int8_t vtype, char* str)
+{
+ u_int8_t len;
+
+ if(radius_get_vs_raw_attr(packet, vendor, vtype, str, &len) != 0)
+ return 1;
+ str[len] = '\0';
+ return 0;
+}
+
+int radius_put_vs_string_attr(RADIUS_PACKET* packet, u_int32_t vendor,
+ u_int8_t vtype, const char* str)
+{
+ return radius_put_vs_raw_attr(packet, vendor, vtype, str, strlen(str));
+}
+
+int radius_get_ipv4_attr(const RADIUS_PACKET* packet, u_int8_t type,
+ struct in_addr* addr)
+{
+ struct in_addr tmp;
+ u_int8_t len;
+
+ if(radius_get_raw_attr(packet, type, &tmp, &len) != 0)
+ return 1;
+ if(len != sizeof(struct in_addr))
+ return 1;
+ *addr = tmp;
+ return 0;
+}
+
+struct in_addr radius_get_ipv4_attr_retval(const RADIUS_PACKET* packet,
+ u_int8_t type)
+{
+ struct in_addr addr;
+ u_int8_t len;
+
+ if(radius_get_raw_attr(packet, type, &addr, &len) != 0)
+ addr.s_addr = htonl(INADDR_ANY);
+ if(len != sizeof(struct in_addr))
+ addr.s_addr = htonl(INADDR_ANY);
+ return addr;
+}
+
+int radius_put_ipv4_attr(RADIUS_PACKET* packet, u_int8_t type, struct in_addr addr)
+{
+ return radius_put_raw_attr(packet, type, &addr, sizeof(struct in_addr));
+}
+
+RADIUS_PACKET* radius_recvfrom(int s, int flags, struct sockaddr* addr, socklen_t* len)
+{
+ char buf[0x10000];
+ ssize_t n;
+
+ n = recvfrom(s, buf, sizeof(buf), flags, addr, len);
+ if(n <= 0)
+ return NULL;
+
+ return radius_convert_packet(buf, (size_t)n);
+}
+
+int radius_sendto(int s, const RADIUS_PACKET* packet,
+ int flags, const struct sockaddr* addr, socklen_t len)
+{
+ ssize_t n;
+
+ n = sendto(s, packet->pdata, radius_get_length(packet), flags, addr, len);
+ if(n != radius_get_length(packet))
+ return 1;
+ return 0;
+}
+
+/**
+ * Calculate keyed-hashing for message authenticaiton using md5.
+ *
+ * @param packet pointer to target RADIUS_PACKET.
+ * @param text_len length of data stream
+ * @param key pointer to authentication key
+ * @param key_len length of authentication key
+ * @param digest caller digest to be filled in
+ */
+static void
+radius_hmac_md5(RADIUS_PACKET *packet, const char * key, int key_len,
+ caddr_t digest, int check)
+{
+ const RADIUS_ATTRIBUTE* attr;
+ const RADIUS_ATTRIBUTE* end;
+ MD5_CTX context;
+ u_char k_ipad[65]; /* inner padding - key XORd with ipad */
+ u_char k_opad[65]; /* outer padding - key XORd with opad */
+ u_char key0[64];
+ int i;
+ u_char zero16[16];
+
+ /* if key is longer than 64 bytes reset it to key=MD5(key) */
+ if (key_len > 64)
+ {
+ MD5_CTX tctx;
+
+ MD5Init(&tctx);
+ MD5Update(&tctx, (const u_char *)key, key_len);
+ MD5Final((u_char *)key0, &tctx);
+
+ key_len = 16;
+ } else
+ memcpy(key0, key, key_len);
+
+ key = (const char *)key0;
+
+ /*
+ * the HMAC_MD5 transform looks like:
+ *
+ * MD5(K XOR opad, MD5(K XOR ipad, text))
+ *
+ * where K is an n byte key
+ * ipad is the byte 0x36 repeated 64 times
+ * opad is the byte 0x5c repeated 64 times
+ * and text is the data being protected
+ */
+
+ /* start out by storing key in pads */
+ memset(k_ipad, 0, sizeof k_ipad);
+ memset(k_opad, 0, sizeof k_opad);
+ memcpy(k_ipad, key, key_len);
+ memcpy(k_opad, key, key_len);
+
+ /* XOR key with ipad and opad values */
+ for (i = 0; i < 64; i++)
+ {
+ k_ipad[i] ^= 0x36;
+ k_opad[i] ^= 0x5c;
+ }
+
+ /* perform inner MD5 */
+ MD5Init(&context); /* init context for 1st pass */
+ MD5Update(&context, k_ipad, 64); /* start with inner pad */
+
+ /*
+ * Traverse the radius packet.
+ */
+ if (check)
+ {
+ MD5Update(&context, (const u_char *)packet->pdata, 4);
+ MD5Update(&context, (unsigned char*)packet->request->pdata
+ ->authenticator, 16);
+ }
+ else
+ {
+ MD5Update(&context, (const u_char *)packet->pdata,
+ sizeof(RADIUS_PACKET_DATA));
+ }
+
+ attr = ATTRS_BEGIN(packet->pdata);
+ end = ATTRS_END(packet->pdata);
+ memset(zero16, 0, sizeof(zero16));
+
+ for(; attr<end; ADVANCE(attr))
+ {
+ if (attr->type == RADIUS_TYPE_MESSAGE_AUTHENTICATOR)
+ {
+ MD5Update(&context, (u_char *)attr, 2);
+ MD5Update(&context, (u_char *)zero16, sizeof(zero16));
+ } else
+ MD5Update(&context, (u_char *)attr, (int)attr->length);
+ }
+
+ MD5Final((u_char *)digest, &context); /* finish up 1st pass */
+ /*
+ * perform outer MD5
+ */
+ MD5Init(&context); /* init context for 2nd pass */
+ MD5Update(&context, k_opad, 64); /* start with outer pad */
+ MD5Update(&context, (u_char *)digest, 16);/* then results of 1st hash */
+ MD5Final((u_char *)digest, &context); /* finish up 2nd pass */
+}
+
+/* RFC 3579 */
+int radius_put_message_authenticator(RADIUS_PACKET *packet, const char *secret)
+{
+ int rval;
+ u_char md5result[16];
+ RADIUS_ATTRIBUTE* attr;
+ RADIUS_ATTRIBUTE* end;
+
+ if ((rval = radius_put_raw_attr(packet,
+ RADIUS_TYPE_MESSAGE_AUTHENTICATOR, md5result, sizeof(md5result)))
+ != 0)
+ return rval;
+
+ radius_hmac_md5(packet, secret, strlen(secret), (caddr_t)md5result, 0);
+
+ attr = ATTRS_BEGIN(packet->pdata);
+ end = ATTRS_END(packet->pdata);
+
+ for(; attr<end; ADVANCE(attr))
+ {
+ if (attr->type == RADIUS_TYPE_MESSAGE_AUTHENTICATOR)
+ {
+ memcpy(attr->data, md5result, sizeof(md5result));
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int radius_check_message_authenticator(RADIUS_PACKET *packet,
+ const char *secret)
+{
+ int rval;
+ u_char len, md5result0[16], md5result1[16];
+
+ radius_hmac_md5(packet, secret, strlen(secret), (caddr_t)md5result0,
+ 1);
+
+ if ((rval = radius_get_raw_attr(packet,
+ RADIUS_TYPE_MESSAGE_AUTHENTICATOR, md5result1, &len)) != 0)
+ return rval;
+
+ if (len != sizeof(md5result1))
+ return -1;
+
+ return memcmp(md5result0, md5result1, sizeof(md5result1));
+}