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

📄 radius.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * radius.c	Functions to send/receive radius packets. * * Version:	$Id: radius.c,v 1.219 2008/04/11 09:55:02 aland Exp $ * *   This library is free software; you can redistribute it and/or *   modify it under the terms of the GNU Lesser General Public *   License as published by the Free Software Foundation; either *   version 2.1 of the License, or (at your option) any later version. * *   This library is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *   Lesser General Public License for more details. * *   You should have received a copy of the GNU Lesser General Public *   License along with this library; if not, write to the Free Software *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000-2003,2006  The FreeRADIUS server project */#include	<freeradius-devel/ident.h>RCSID("$Id: radius.c,v 1.219 2008/04/11 09:55:02 aland Exp $")#include	<freeradius-devel/libradius.h>#include	<freeradius-devel/md5.h>#include	<fcntl.h>#include	<ctype.h>#ifdef WITH_UDPFROMTO#include	<freeradius-devel/udpfromto.h>#endif#ifdef HAVE_MALLOC_H#include	<malloc.h>#endif/* *  The RFC says 4096 octets max, and most packets are less than 256. */#define MAX_PACKET_LEN 4096/* *	The maximum number of attributes which we allow in an incoming *	request.  If there are more attributes than this, the request *	is rejected. * *	This helps to minimize the potential for a DoS, when an *	attacker spoofs Access-Request packets, which don't have a *	Message-Authenticator attribute.  This means that the packet *	is unsigned, and the attacker can use resources on the server, *	even if the end request is rejected. */int librad_max_attributes = 0;FILE *fr_log_fp = NULL;typedef struct radius_packet_t {  uint8_t	code;  uint8_t	id;  uint8_t	length[2];  uint8_t	vector[AUTH_VECTOR_LEN];  uint8_t	data[1];} radius_packet_t;static fr_randctx fr_rand_pool;	/* across multiple calls */static int fr_rand_initialized = 0;static unsigned int salt_offset = 0;#define MAX_PACKET_CODE (52)static const char *packet_codes[] = {  "",  "Access-Request",  "Access-Accept",  "Access-Reject",  "Accounting-Request",  "Accounting-Response",  "Accounting-Status",  "Password-Request",  "Password-Accept",  "Password-Reject",  "Accounting-Message",  "Access-Challenge",  "Status-Server",  "Status-Client",  "14",  "15",  "16",  "17",  "18",  "19",  "20",  "Resource-Free-Request",  "Resource-Free-Response",  "Resource-Query-Request",  "Resource-Query-Response",  "Alternate-Resource-Reclaim-Request",  "NAS-Reboot-Request",  "NAS-Reboot-Response",  "28",  "Next-Passcode",  "New-Pin",  "Terminate-Session",  "Password-Expired",  "Event-Request",  "Event-Response",  "35",  "36",  "37",  "38",  "39",  "Disconnect-Request",  "Disconnect-ACK",  "Disconnect-NAK",  "CoA-Request",  "CoA-ACK",  "CoA-NAK",  "46",  "47",  "48",  "49",  "IP-Address-Allocate",  "IP-Address-Release"};void fr_printf_log(const char *fmt, ...){	va_list ap;	va_start(ap, fmt);	if ((librad_debug == 0) || !fr_log_fp) {		va_end(ap);		return;	}	vfprintf(fr_log_fp, fmt, ap);	va_end(ap);	return;}/* *	Wrapper for sendto which handles sendfromto, IPv6, and all *	possible combinations. */static int rad_sendto(int sockfd, void *data, size_t data_len, int flags,		      fr_ipaddr_t *src_ipaddr, int src_port,		      fr_ipaddr_t *dst_ipaddr, int dst_port){	struct sockaddr_storage	dst;	socklen_t		sizeof_dst = sizeof(dst);#ifdef WITH_UDPFROMTO	struct sockaddr_storage	src;	socklen_t		sizeof_src = sizeof(src);	memset(&src, 0, sizeof(src));#endif	memset(&dst, 0, sizeof(dst));	/*	 *	IPv4 is supported.	 */	if (dst_ipaddr->af == AF_INET) {		struct sockaddr_in	*s4;		s4 = (struct sockaddr_in *)&dst;		sizeof_dst = sizeof(struct sockaddr_in);		s4->sin_family = AF_INET;		s4->sin_addr = dst_ipaddr->ipaddr.ip4addr;		s4->sin_port = htons(dst_port);#ifdef WITH_UDPFROMTO		s4 = (struct sockaddr_in *)&src;		sizeof_src = sizeof(struct sockaddr_in);		s4->sin_family = AF_INET;		s4->sin_addr = src_ipaddr->ipaddr.ip4addr;		s4->sin_port = htons(src_port);#else		src_port = src_port; /* -Wunused */#endif	/*	 *	IPv6 MAY be supported.	 */#ifdef HAVE_STRUCT_SOCKADDR_IN6	} else if (dst_ipaddr->af == AF_INET6) {		struct sockaddr_in6	*s6;		s6 = (struct sockaddr_in6 *)&dst;		sizeof_dst = sizeof(struct sockaddr_in6);		s6->sin6_family = AF_INET6;		s6->sin6_addr = dst_ipaddr->ipaddr.ip6addr;		s6->sin6_port = htons(dst_port);#ifdef WITH_UDPFROMTO		return -1;	/* UDPFROMTO && IPv6 are not supported */#if 0		s6 = (struct sockaddr_in6 *)&src;		sizeof_src = sizeof(struct sockaddr_in6);		s6->sin6_family = AF_INET6;		s6->sin6_addr = src_ipaddr->ipaddr.ip6addr;#endif /* #if 0 */#endif /* WITH_UDPFROMTO */#endif /* HAVE_STRUCT_SOCKADDR_IN6 */	} else return -1;   /* Unknown address family, Die Die Die! */#ifdef WITH_UDPFROMTO	/*	 *	Only IPv4 is supported for udpfromto.	 *	 *	And if they don't specify a source IP address, don't	 *	use udpfromto.	 */	if ((dst_ipaddr->af == AF_INET) ||	    (src_ipaddr->af != AF_UNSPEC)) {		return sendfromto(sockfd, data, data_len, flags,				  (struct sockaddr *)&src, sizeof_src,				  (struct sockaddr *)&dst, sizeof_dst);	}#else	src_ipaddr = src_ipaddr; /* -Wunused */#endif	/*	 *	No udpfromto, OR an IPv6 socket, fail gracefully.	 */	return sendto(sockfd, data, data_len, flags,		      (struct sockaddr *)&dst, sizeof_dst);}void rad_recv_discard(int sockfd){	uint8_t			header[4];	struct sockaddr_storage	src;	socklen_t		sizeof_src = sizeof(src);	recvfrom(sockfd, header, sizeof(header), 0,		 (struct sockaddr *)&src, &sizeof_src);}ssize_t rad_recv_header(int sockfd, fr_ipaddr_t *src_ipaddr, int *src_port,			int *code){	ssize_t			data_len, packet_len;	uint8_t			header[4];	struct sockaddr_storage	src;	socklen_t		sizeof_src = sizeof(src);	data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK,			    (struct sockaddr *)&src, &sizeof_src);	if (data_len < 0) {		if ((errno == EAGAIN) || (errno == EINTR)) return 0;		return -1;	}	/*	 *	Too little data is available, discard the packet.	 */	if (data_len < 4) {		recvfrom(sockfd, header, sizeof(header), 0,			 (struct sockaddr *)&src, &sizeof_src);		return 1;	} else {		/* we got 4 bytes of data. */		/*		 *	See how long the packet says it is.		 */		packet_len = (header[2] * 256) + header[3];		/*		 *	The length in the packet says it's less than		 *	a RADIUS header length: discard it.		 */		if (packet_len < AUTH_HDR_LEN) {			recvfrom(sockfd, header, sizeof(header), 0,				 (struct sockaddr *)&src, &sizeof_src);			return 1;			/*			 *	Enforce RFC requirements, for sanity.			 *	Anything after 4k will be discarded.			 */		} else if (packet_len > MAX_PACKET_LEN) {			recvfrom(sockfd, header, sizeof(header), 0,				 (struct sockaddr *)&src, &sizeof_src);			return 1;		}	}	if (src.ss_family == AF_INET) {		struct sockaddr_in	*s4;		s4 = (struct sockaddr_in *)&src;		src_ipaddr->af = AF_INET;		src_ipaddr->ipaddr.ip4addr = s4->sin_addr;		*src_port = ntohs(s4->sin_port);#ifdef HAVE_STRUCT_SOCKADDR_IN6	} else if (src.ss_family == AF_INET6) {		struct sockaddr_in6	*s6;		s6 = (struct sockaddr_in6 *)&src;		src_ipaddr->af = AF_INET6;		src_ipaddr->ipaddr.ip6addr = s6->sin6_addr;		*src_port = ntohs(s6->sin6_port);#endif	} else {		recvfrom(sockfd, header, sizeof(header), 0,			 (struct sockaddr *)&src, &sizeof_src);		return 1;	}	*code = header[0];	/*	 *	The packet says it's this long, but the actual UDP	 *	size could still be smaller.	 */	return packet_len;}/* *	wrapper for recvfrom, which handles recvfromto, IPv6, and all *	possible combinations. */static ssize_t rad_recvfrom(int sockfd, uint8_t **pbuf, int flags,			    fr_ipaddr_t *src_ipaddr, uint16_t *src_port,			    fr_ipaddr_t *dst_ipaddr, uint16_t *dst_port){	struct sockaddr_storage	src;	struct sockaddr_storage	dst;	socklen_t		sizeof_src = sizeof(src);	socklen_t	        sizeof_dst = sizeof(dst);	ssize_t			data_len;	uint8_t			header[4];	void			*buf;	size_t			len;	memset(&src, 0, sizeof_src);	memset(&dst, 0, sizeof_dst);	/*	 *	Get address family, etc. first, so we know if we	 *	need to do udpfromto.	 *	 *	FIXME: udpfromto also does this, but it's not	 *	a critical problem.	 */	if (getsockname(sockfd, (struct sockaddr *)&dst,			&sizeof_dst) < 0) return -1;	/*	 *	Read the length of the packet, from the packet.	 *	This lets us allocate the buffer to use for	 *	reading the rest of the packet.	 */	data_len = recvfrom(sockfd, header, sizeof(header), MSG_PEEK,			    (struct sockaddr *)&src, &sizeof_src);	if (data_len < 0) {		if ((errno == EAGAIN) || (errno == EINTR)) return 0;		return -1;	}	/*	 *	Too little data is available, discard the packet.	 */	if (data_len < 4) {		recvfrom(sockfd, header, sizeof(header), flags,			 (struct sockaddr *)&src, &sizeof_src);		return 0;	} else {		/* we got 4 bytes of data. */		/*		 *	See how long the packet says it is.		 */		len = (header[2] * 256) + header[3];		/*		 *	The length in the packet says it's less than		 *	a RADIUS header length: discard it.		 */		if (len < AUTH_HDR_LEN) {			recvfrom(sockfd, header, sizeof(header), flags,				 (struct sockaddr *)&src, &sizeof_src);			return 0;			/*			 *	Enforce RFC requirements, for sanity.			 *	Anything after 4k will be discarded.			 */		} else if (len > MAX_PACKET_LEN) {			recvfrom(sockfd, header, sizeof(header), flags,				 (struct sockaddr *)&src, &sizeof_src);			return len;		}	}	buf = malloc(len);	if (!buf) return -1;	/*	 *	Receive the packet.  The OS will discard any data in the	 *	packet after "len" bytes.	 */#ifdef WITH_UDPFROMTO	if (dst.ss_family == AF_INET) {		data_len = recvfromto(sockfd, buf, len, flags,				      (struct sockaddr *)&src, &sizeof_src,				      (struct sockaddr *)&dst, &sizeof_dst);	} else#endif		/*		 *	No udpfromto, OR an IPv6 socket.  Fail gracefully.		 */		data_len = recvfrom(sockfd, buf, len, flags,				    (struct sockaddr *)&src, &sizeof_src);	if (data_len < 0) {		free(buf);		return data_len;	}	/*	 *	Check address families, and update src/dst ports, etc.	 */	if (src.ss_family == AF_INET) {		struct sockaddr_in	*s4;		s4 = (struct sockaddr_in *)&src;		src_ipaddr->af = AF_INET;		src_ipaddr->ipaddr.ip4addr = s4->sin_addr;		*src_port = ntohs(s4->sin_port);		s4 = (struct sockaddr_in *)&dst;		dst_ipaddr->af = AF_INET;		dst_ipaddr->ipaddr.ip4addr = s4->sin_addr;		*dst_port = ntohs(s4->sin_port);#ifdef HAVE_STRUCT_SOCKADDR_IN6	} else if (src.ss_family == AF_INET6) {		struct sockaddr_in6	*s6;		s6 = (struct sockaddr_in6 *)&src;		src_ipaddr->af = AF_INET6;		src_ipaddr->ipaddr.ip6addr = s6->sin6_addr;		*src_port = ntohs(s6->sin6_port);		s6 = (struct sockaddr_in6 *)&dst;		dst_ipaddr->af = AF_INET6;		dst_ipaddr->ipaddr.ip6addr = s6->sin6_addr;		*dst_port = ntohs(s6->sin6_port);#endif	} else {		free(buf);		return -1;	/* Unknown address family, Die Die Die! */	}	/*	 *	Different address families should never happen.	 */	if (src.ss_family != dst.ss_family) {		free(buf);		return -1;	}	/*	 *	Tell the caller about the data	 */	*pbuf = buf;	return data_len;}#define AUTH_PASS_LEN (AUTH_VECTOR_LEN)/************************************************************************* * *      Function: make_secret * *      Purpose: Build an encrypted secret value to return in a reply *               packet.  The secret is hidden by xoring with a MD5 digest *               created from the shared secret and the authentication *               vector.  We put them into MD5 in the reverse order from *               that used when encrypting passwords to RADIUS. * *************************************************************************/static void make_secret(uint8_t *digest, const uint8_t *vector,			const char *secret, const uint8_t *value){	FR_MD5_CTX context;        int             i;	fr_MD5Init(&context);	fr_MD5Update(&context, vector, AUTH_VECTOR_LEN);	fr_MD5Update(&context, (const uint8_t *) secret, strlen(secret));	fr_MD5Final(digest, &context);        for ( i = 0; i < AUTH_VECTOR_LEN; i++ ) {		digest[i] ^= value[i];        }}#define MAX_PASS_LEN (128)static void make_passwd(uint8_t *output, int *outlen,			const uint8_t *input, int inlen,			const char *secret, const uint8_t *vector){	FR_MD5_CTX context, old;	uint8_t	digest[AUTH_VECTOR_LEN];	uint8_t passwd[MAX_PASS_LEN];	int	i, n;	int	len;	/*	 *	If the length is zero, round it up.	 */	len = inlen;	if (len == 0) {		len = AUTH_PASS_LEN;	}	else if (len > MAX_PASS_LEN) len = MAX_PASS_LEN;	else if ((len & 0x0f) != 0) {		len += 0x0f;		len &= ~0x0f;	}	*outlen = len;	memcpy(passwd, input, len);	memset(passwd + len, 0, sizeof(passwd) - len);	fr_MD5Init(&context);	fr_MD5Update(&context, (const uint8_t *) secret, strlen(secret));	old = context;	/*	 *	Do first pass.	 */	fr_MD5Update(&context, vector, AUTH_PASS_LEN);	for (n = 0; n < len; n += AUTH_PASS_LEN) {		if (n > 0) {			context = old;			fr_MD5Update(&context,				       passwd + n - AUTH_PASS_LEN,				       AUTH_PASS_LEN);		}		fr_MD5Final(digest, &context);		for (i = 0; i < AUTH_PASS_LEN; i++) {			passwd[i + n] ^= digest[i];

⌨️ 快捷键说明

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