⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 radius.c

📁 802.1x 源码,基于linux平台开发
💻 C
📖 第 1 页 / 共 2 页
字号:
/*
 *
 * 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 + -