📄 radius.c
字号:
/*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation. See README and COPYING for
* more details.
Module Name:
radius.c
Revision History:
Who When What
-------- ---------- ----------------------------------------------
Jan, Lee Dec --2003 modified
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <netinet/in.h>
#include <string.h>
#include <sys/ioctl.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include "common.h"
#include "radius.h"
#include "md5.h"
#include "rt61apd.h"
struct radius_msg *Radius_msg_new(u8 code, u8 identifier)
{
struct radius_msg *msg;
msg = (struct radius_msg *) malloc(sizeof(*msg));
if (msg == NULL)
return NULL;
if (Radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE))
{
free(msg);
return NULL;
}
Radius_msg_set_hdr(msg, code, identifier);
return msg;
}
int Radius_msg_initialize(struct radius_msg *msg, size_t init_len)
{
if (msg == NULL || init_len < sizeof(struct radius_hdr))
return -1;
memset(msg, 0, sizeof(*msg));
msg->buf = (unsigned char *) malloc(init_len);
if (msg->buf == NULL)
return -1;
memset(msg->buf, 0, init_len);
msg->buf_size = init_len;
msg->hdr = (struct radius_hdr *) msg->buf;
msg->buf_used = sizeof(*msg->hdr);
msg->attrs = (struct radius_attr_hdr **)
malloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attrs));
if (msg->attrs == NULL)
{
free(msg->buf);
msg->buf = NULL;
msg->hdr = NULL;
return -1;
}
msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
msg->attr_used = 0;
return 0;
}
void Radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
{
msg->hdr->code = code;
msg->hdr->identifier = identifier;
}
void Radius_msg_free(struct radius_msg *msg)
{
if (msg->buf != NULL)
{
free(msg->buf);
msg->buf = NULL;
msg->hdr = NULL;
}
msg->buf_size = msg->buf_used = 0;
if (msg->attrs != NULL)
{
free(msg->attrs);
msg->attrs = NULL;
}
msg->attr_size = msg->attr_used = 0;
}
struct radius_attr_type {
u8 type;
char *name;
enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32 } data_type;
};
void Radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len)
{
if (secret)
{
char auth[MD5_MAC_LEN];
struct radius_attr_hdr *attr;
memset(auth, 0, MD5_MAC_LEN);
attr = Radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN);
msg->hdr->length = htons(msg->buf_used);
hmac_md5(secret, secret_len, msg->buf, msg->buf_used, (u8 *) (attr + 1));
}
else
msg->hdr->length = htons(msg->buf_used);
if (msg->buf_used > 0xffff)
{
DBGPRINT(RT_DEBUG_ERROR,"WARNING: too long RADIUS messages (%d)\n", msg->buf_used);
}
}
static int Radius_msg_add_attr_to_array(struct radius_msg *msg, struct radius_attr_hdr *attr)
{
if (msg->attr_used >= msg->attr_size)
{
struct radius_attr_hdr **nattrs;
int nlen = msg->attr_size * 2;
nattrs = (struct radius_attr_hdr **) realloc(msg->attrs, nlen * sizeof(*msg->attrs));
if (nattrs == NULL)
return -1;
msg->attrs = nattrs;
msg->attr_size = nlen;
}
msg->attrs[msg->attr_used++] = attr;
return 0;
}
struct radius_attr_hdr *Radius_msg_add_attr(struct radius_msg *msg, u8 type, u8 *data, size_t data_len)
{
size_t buf_needed;
struct radius_attr_hdr *attr;
if (data_len > RADIUS_MAX_ATTR_LEN)
{
DBGPRINT(RT_DEBUG_ERROR,"radius_msg_add_attr: too long attribute (%d bytes)\n", data_len);
return NULL;
}
buf_needed = msg->buf_used + sizeof(*attr) + data_len;
if (msg->buf_size < buf_needed)
{
/* allocate more space for message buffer */
unsigned char *nbuf;
int nlen = msg->buf_size;
int diff, i;
while (nlen < buf_needed)
nlen *= 2;
nbuf = (unsigned char *) realloc(msg->buf, nlen);
if (nbuf == NULL)
return NULL;
diff = nbuf - msg->buf;
msg->buf = nbuf;
msg->hdr = (struct radius_hdr *) msg->buf;
/* adjust attr pointers to match with the new buffer */
for (i = 0; i < msg->attr_used; i++)
msg->attrs[i] = (struct radius_attr_hdr *) (((u8 *) msg->attrs[i]) + diff);
memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
msg->buf_size = nlen;
}
attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
attr->type = type;
attr->length = sizeof(*attr) + data_len;
if (data_len > 0)
memcpy(attr + 1, data, data_len);
msg->buf_used += sizeof(*attr) + data_len;
if (Radius_msg_add_attr_to_array(msg, attr))
return NULL;
return attr;
}
struct radius_msg *Radius_msg_parse(const u8 *data, size_t len)
{
struct radius_msg *msg;
struct radius_hdr *hdr;
struct radius_attr_hdr *attr;
size_t msg_len;
unsigned char *pos, *end;
if (data == NULL || len < sizeof(*hdr))
return NULL;
hdr = (struct radius_hdr *) data;
msg_len = ntohs(hdr->length);
if (msg_len < sizeof(*hdr) || msg_len > len)
{
DBGPRINT(RT_DEBUG_ERROR,"Invalid RADIUS message length\n");
return NULL;
}
if (msg_len < len)
{
DBGPRINT(RT_DEBUG_INFO,"Ignored %d extra bytes after RADIUS message\n", len - msg_len);
}
msg = (struct radius_msg *) malloc(sizeof(*msg));
if (msg == NULL)
return NULL;
if (Radius_msg_initialize(msg, msg_len))
{
free(msg);
return NULL;
}
memcpy(msg->buf, data, msg_len);
msg->buf_size = msg->buf_used = msg_len;
/* parse attributes */
pos = (unsigned char *) (msg->hdr + 1);
end = msg->buf + msg->buf_used;
while (pos < end)
{
if (end - pos < sizeof(*attr))
goto fail;
attr = (struct radius_attr_hdr *) pos;
if (pos + attr->length > end || attr->length < sizeof(*attr))
goto fail;
/* TODO: check that attr->length is suitable for attr->type */
if (Radius_msg_add_attr_to_array(msg, attr))
goto fail;
pos += attr->length;
}
return msg;
fail:
Radius_msg_free(msg);
free(msg);
return NULL;
}
int Radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len)
{
u8 *pos = data;
size_t left = data_len;
while (left > 0)
{
int len;
if (left > RADIUS_MAX_ATTR_LEN)
len = RADIUS_MAX_ATTR_LEN;
else
len = left;
if (!Radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, pos, len))
return 0;
pos += len;
left -= len;
}
return 1;
}
char *Radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
{
char *eap, *pos;
size_t len;
int i;
if (msg == NULL)
return NULL;
len = 0;
for (i = 0; i < msg->attr_used; i++)
{
if (msg->attrs[i]->type == RADIUS_ATTR_EAP_MESSAGE)
len += msg->attrs[i]->length - sizeof(struct radius_attr_hdr);
}
if (len == 0)
return NULL;
eap = (char *) malloc(len);
if (eap == NULL)
return NULL;
pos = eap;
for (i = 0; i < msg->attr_used; i++)
{
if (msg->attrs[i]->type == RADIUS_ATTR_EAP_MESSAGE)
{
struct radius_attr_hdr *attr = msg->attrs[i];
int flen = attr->length - sizeof(*attr);
memcpy(pos, attr + 1, flen);
pos += flen;
}
}
if (eap_len)
*eap_len = len;
return eap;
}
int Radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len, struct radius_msg *sent_msg)
{
u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
u8 orig_authenticator[16];
struct radius_attr_hdr *attr = NULL;
int i;
MD5_CTX context;
u8 hash[MD5_MAC_LEN];
if (sent_msg == NULL)
{
DBGPRINT(RT_DEBUG_ERROR,"No matching Access-Request message found\n");
return 1;
}
for (i = 0; i < msg->attr_used; i++)
{
if (msg->attrs[i]->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -