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

📄 radius.c

📁 IEEE802.11 a/b/g 客户端应用程序源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * hostapd / RADIUS message processing * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi> * * 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. * * Alternatively, this software may be distributed under the terms of BSD * license. * * See README and COPYING for more details. */#include "includes.h"#include "common.h"#include "radius.h"#include "md5.h"#include "crypto.h"static struct radius_attr_hdr *radius_get_attr_hdr(struct radius_msg *msg, int idx){	return (struct radius_attr_hdr *) (msg->buf + msg->attr_pos[idx]);}struct radius_msg *radius_msg_new(u8 code, u8 identifier){	struct radius_msg *msg;	msg = os_malloc(sizeof(*msg));	if (msg == NULL)		return NULL;	if (radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE)) {		os_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;	os_memset(msg, 0, sizeof(*msg));	msg->buf = os_zalloc(init_len);	if (msg->buf == NULL)		return -1;	msg->buf_size = init_len;	msg->hdr = (struct radius_hdr *) msg->buf;	msg->buf_used = sizeof(*msg->hdr);	msg->attr_pos =		os_zalloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attr_pos));	if (msg->attr_pos == NULL) {		os_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){	os_free(msg->buf);	msg->buf = NULL;	msg->hdr = NULL;	msg->buf_size = msg->buf_used = 0;	os_free(msg->attr_pos);	msg->attr_pos = NULL;	msg->attr_size = msg->attr_used = 0;}static const char *radius_code_string(u8 code){	switch (code) {	case RADIUS_CODE_ACCESS_REQUEST: return "Access-Request";	case RADIUS_CODE_ACCESS_ACCEPT: return "Access-Accept";	case RADIUS_CODE_ACCESS_REJECT: return "Access-Reject";	case RADIUS_CODE_ACCOUNTING_REQUEST: return "Accounting-Request";	case RADIUS_CODE_ACCOUNTING_RESPONSE: return "Accounting-Response";	case RADIUS_CODE_ACCESS_CHALLENGE: return "Access-Challenge";	case RADIUS_CODE_STATUS_SERVER: return "Status-Server";	case RADIUS_CODE_STATUS_CLIENT: return "Status-Client";	case RADIUS_CODE_RESERVED: return "Reserved";	default: return "?Unknown?";	}}struct radius_attr_type {	u8 type;	char *name;	enum {		RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,		RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32, RADIUS_ATTR_IPV6	} data_type;};static struct radius_attr_type radius_attrs[] ={	{ RADIUS_ATTR_USER_NAME, "User-Name", RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_USER_PASSWORD, "User-Password", RADIUS_ATTR_UNDIST },	{ RADIUS_ATTR_NAS_IP_ADDRESS, "NAS-IP-Address", RADIUS_ATTR_IP },	{ RADIUS_ATTR_NAS_PORT, "NAS-Port", RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_FRAMED_MTU, "Framed-MTU", RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_REPLY_MESSAGE, "Reply-Message", RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_STATE, "State", RADIUS_ATTR_UNDIST },	{ RADIUS_ATTR_CLASS, "Class", RADIUS_ATTR_UNDIST },	{ RADIUS_ATTR_VENDOR_SPECIFIC, "Vendor-Specific", RADIUS_ATTR_UNDIST },	{ RADIUS_ATTR_SESSION_TIMEOUT, "Session-Timeout", RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_IDLE_TIMEOUT, "Idle-Timeout", RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_TERMINATION_ACTION, "Termination-Action",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_CALLED_STATION_ID, "Called-Station-Id",	  RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_CALLING_STATION_ID, "Calling-Station-Id",	  RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_NAS_IDENTIFIER, "NAS-Identifier", RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_PROXY_STATE, "Proxy-State", RADIUS_ATTR_UNDIST },	{ RADIUS_ATTR_ACCT_STATUS_TYPE, "Acct-Status-Type",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_DELAY_TIME, "Acct-Delay-Time", RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_INPUT_OCTETS, "Acct-Input-Octets",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_OUTPUT_OCTETS, "Acct-Output-Octets",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_SESSION_ID, "Acct-Session-Id", RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_ACCT_AUTHENTIC, "Acct-Authentic", RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_SESSION_TIME, "Acct-Session-Time",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_INPUT_PACKETS, "Acct-Input-Packets",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_OUTPUT_PACKETS, "Acct-Output-Packets",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_TERMINATE_CAUSE, "Acct-Terminate-Cause",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_MULTI_SESSION_ID, "Acct-Multi-Session-Id",	  RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_ACCT_LINK_COUNT, "Acct-Link-Count", RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_INPUT_GIGAWORDS, "Acct-Input-Gigawords", 	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS, "Acct-Output-Gigawords",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_EVENT_TIMESTAMP, "Event-Timestamp",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_NAS_PORT_TYPE, "NAS-Port-Type", RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_TUNNEL_TYPE, "Tunnel-Type", RADIUS_ATTR_HEXDUMP },	{ RADIUS_ATTR_TUNNEL_MEDIUM_TYPE, "Tunnel-Medium-Type",	  RADIUS_ATTR_HEXDUMP },	{ RADIUS_ATTR_CONNECT_INFO, "Connect-Info", RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_EAP_MESSAGE, "EAP-Message", RADIUS_ATTR_UNDIST },	{ RADIUS_ATTR_MESSAGE_AUTHENTICATOR, "Message-Authenticator",	  RADIUS_ATTR_UNDIST },	{ RADIUS_ATTR_TUNNEL_PRIVATE_GROUP_ID, "Tunnel-Private-Group-Id",	  RADIUS_ATTR_HEXDUMP },	{ RADIUS_ATTR_ACCT_INTERIM_INTERVAL, "Acct-Interim-Interval",	  RADIUS_ATTR_INT32 },	{ RADIUS_ATTR_CHARGEABLE_USER_IDENTITY, "Chargable-User-Identity",	  RADIUS_ATTR_TEXT },	{ RADIUS_ATTR_NAS_IPV6_ADDRESS, "NAS-IPv6-Address", RADIUS_ATTR_IPV6 },};#define RADIUS_ATTRS (sizeof(radius_attrs) / sizeof(radius_attrs[0]))static struct radius_attr_type *radius_get_attr_type(u8 type){	size_t i;	for (i = 0; i < RADIUS_ATTRS; i++) {		if (type == radius_attrs[i].type)			return &radius_attrs[i];	}	return NULL;}static void print_char(char c){	if (c >= 32 && c < 127)		printf("%c", c);	else		printf("<%02x>", c);}static void radius_msg_dump_attr(struct radius_attr_hdr *hdr){	struct radius_attr_type *attr;	int i, len;	unsigned char *pos;	attr = radius_get_attr_type(hdr->type);	printf("   Attribute %d (%s) length=%d\n",	       hdr->type, attr ? attr->name : "?Unknown?", hdr->length);	if (attr == NULL)		return;	len = hdr->length - sizeof(struct radius_attr_hdr);	pos = (unsigned char *) (hdr + 1);	switch (attr->data_type) {	case RADIUS_ATTR_TEXT:		printf("      Value: '");		for (i = 0; i < len; i++)			print_char(pos[i]);		printf("'\n");		break;	case RADIUS_ATTR_IP:		if (len == 4) {			struct in_addr addr;			os_memcpy(&addr, pos, 4);			printf("      Value: %s\n", inet_ntoa(addr));		} else			printf("      Invalid IP address length %d\n", len);		break;#ifdef CONFIG_IPV6	case RADIUS_ATTR_IPV6:		if (len == 16) {			char buf[128];			const char *atxt;			struct in6_addr *addr = (struct in6_addr *) pos;			atxt = inet_ntop(AF_INET6, addr, buf, sizeof(buf));			printf("      Value: %s\n", atxt ? atxt : "?");		} else			printf("      Invalid IPv6 address length %d\n", len);		break;#endif /* CONFIG_IPV6 */	case RADIUS_ATTR_HEXDUMP:	case RADIUS_ATTR_UNDIST:		printf("      Value:");		for (i = 0; i < len; i++)			printf(" %02x", pos[i]);		printf("\n");		break;	case RADIUS_ATTR_INT32:		if (len == 4)			printf("      Value: %u\n", WPA_GET_BE32(pos));		else			printf("      Invalid INT32 length %d\n", len);		break;	default:		break;	}}void radius_msg_dump(struct radius_msg *msg){	size_t i;	printf("RADIUS message: code=%d (%s) identifier=%d length=%d\n",	       msg->hdr->code, radius_code_string(msg->hdr->code),	       msg->hdr->identifier, ntohs(msg->hdr->length));	for (i = 0; i < msg->attr_used; i++) {		struct radius_attr_hdr *attr = radius_get_attr_hdr(msg, i);		radius_msg_dump_attr(attr);	}}int radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len){	if (secret) {		u8 auth[MD5_MAC_LEN];		struct radius_attr_hdr *attr;		os_memset(auth, 0, MD5_MAC_LEN);		attr = radius_msg_add_attr(msg,					   RADIUS_ATTR_MESSAGE_AUTHENTICATOR,					   auth, MD5_MAC_LEN);		if (attr == NULL) {			printf("WARNING: Could not add "			       "Message-Authenticator\n");			return -1;		}		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) {		printf("WARNING: too long RADIUS message (%lu)\n",		       (unsigned long) msg->buf_used);		return -1;	}	return 0;}int radius_msg_finish_srv(struct radius_msg *msg, const u8 *secret,			  size_t secret_len, const u8 *req_authenticator){	u8 auth[MD5_MAC_LEN];	struct radius_attr_hdr *attr;	const u8 *addr[4];	size_t len[4];	os_memset(auth, 0, MD5_MAC_LEN);	attr = radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR,				   auth, MD5_MAC_LEN);	if (attr == NULL) {		printf("WARNING: Could not add Message-Authenticator\n");		return -1;	}	msg->hdr->length = htons(msg->buf_used);	os_memcpy(msg->hdr->authenticator, req_authenticator,		  sizeof(msg->hdr->authenticator));	hmac_md5(secret, secret_len, msg->buf, msg->buf_used,		 (u8 *) (attr + 1));	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */	addr[0] = (u8 *) msg->hdr;	len[0] = 1 + 1 + 2;	addr[1] = req_authenticator;	len[1] = MD5_MAC_LEN;	addr[2] = (u8 *) (msg->hdr + 1);	len[2] = msg->buf_used - sizeof(*msg->hdr);	addr[3] = secret;	len[3] = secret_len;	md5_vector(4, addr, len, msg->hdr->authenticator);	if (msg->buf_used > 0xffff) {		printf("WARNING: too long RADIUS message (%lu)\n",		       (unsigned long) msg->buf_used);		return -1;	}	return 0;}void radius_msg_finish_acct(struct radius_msg *msg, u8 *secret,			    size_t secret_len){	const u8 *addr[2];	size_t len[2];	msg->hdr->length = htons(msg->buf_used);	os_memset(msg->hdr->authenticator, 0, MD5_MAC_LEN);	addr[0] = msg->buf;	len[0] = msg->buf_used;	addr[1] = secret;	len[1] = secret_len;	md5_vector(2, addr, len, msg->hdr->authenticator);	if (msg->buf_used > 0xffff) {		printf("WARNING: too long RADIUS messages (%lu)\n",		       (unsigned long) 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) {		size_t *nattr_pos;		int nlen = msg->attr_size * 2;		nattr_pos = os_realloc(msg->attr_pos,				       nlen * sizeof(*msg->attr_pos));		if (nattr_pos == NULL)			return -1;		msg->attr_pos = nattr_pos;		msg->attr_size = nlen;	}	msg->attr_pos[msg->attr_used++] = (unsigned char *) attr - msg->buf;	return 0;}struct radius_attr_hdr *radius_msg_add_attr(struct radius_msg *msg, u8 type,					    const u8 *data, size_t data_len){	size_t buf_needed;	struct radius_attr_hdr *attr;	if (data_len > RADIUS_MAX_ATTR_LEN) {		printf("radius_msg_add_attr: too long attribute (%lu bytes)\n",		       (unsigned long) 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;		size_t nlen = msg->buf_size;		while (nlen < buf_needed)			nlen *= 2;		nbuf = os_realloc(msg->buf, nlen);		if (nbuf == NULL)			return NULL;		msg->buf = nbuf;		msg->hdr = (struct radius_hdr *) msg->buf;		os_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)		os_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) {		printf("Invalid RADIUS message length\n");		return NULL;	}	if (msg_len < len) {		printf("Ignored %lu extra bytes after RADIUS message\n",		       (unsigned long) len - msg_len);	}	msg = os_malloc(sizeof(*msg));	if (msg == NULL)		return NULL;	if (radius_msg_initialize(msg, msg_len)) {		os_free(msg);		return NULL;	}	os_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 ((size_t) (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);	os_free(msg);	return NULL;}int radius_msg_add_eap(struct radius_msg *msg, const u8 *data, size_t data_len){	const 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;}u8 *radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len){	u8 *eap, *pos;	size_t len, i;	struct radius_attr_hdr *attr;	if (msg == NULL)		return NULL;	len = 0;	for (i = 0; i < msg->attr_used; i++) {		attr = radius_get_attr_hdr(msg, i);		if (attr->type == RADIUS_ATTR_EAP_MESSAGE)			len += attr->length - sizeof(struct radius_attr_hdr);	}	if (len == 0)		return NULL;	eap = os_malloc(len);	if (eap == NULL)		return NULL;	pos = eap;	for (i = 0; i < msg->attr_used; i++) {		attr = radius_get_attr_hdr(msg, i);		if (attr->type == RADIUS_ATTR_EAP_MESSAGE) {			int flen = attr->length - sizeof(*attr);			os_memcpy(pos, attr + 1, flen);			pos += flen;		}	}	if (eap_len)		*eap_len = len;	return eap;}int radius_msg_verify_msg_auth(struct radius_msg *msg, const u8 *secret,			       size_t secret_len, const u8 *req_auth){	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];	u8 orig_authenticator[16];	struct radius_attr_hdr *attr = NULL, *tmp;	size_t i;	for (i = 0; i < msg->attr_used; i++) {		tmp = radius_get_attr_hdr(msg, i);		if (tmp->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR) {			if (attr != NULL) {				printf("Multiple Message-Authenticator "				       "attributes in RADIUS message\n");				return 1;			}			attr = tmp;		}	}	if (attr == NULL) {		printf("No Message-Authenticator attribute found\n");		return 1;	}	os_memcpy(orig, attr + 1, MD5_MAC_LEN);	os_memset(attr + 1, 0, MD5_MAC_LEN);	if (req_auth) {		os_memcpy(orig_authenticator, msg->hdr->authenticator,			  sizeof(orig_authenticator));		os_memcpy(msg->hdr->authenticator, req_auth,			  sizeof(msg->hdr->authenticator));	}	hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -