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

📄 radius.c

📁 新的radius程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * radius.c	Functions to send/receive radius packets. * * Version:	$Id: radius.c,v 1.125.2.5.2.10 2007/02/13 09:37:12 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  The FreeRADIUS server project */static const char rcsid[] = "$Id: radius.c,v 1.125.2.5.2.10 2007/02/13 09:37:12 aland Exp $";#include	"autoconf.h"#include	"md5.h"#include	<stdlib.h>#ifdef HAVE_UNISTD_H#include	<unistd.h>#endif#include	<fcntl.h>#include	<string.h>#include	<ctype.h>#include	"libradius.h"#ifdef WITH_UDPFROMTO#include	"udpfromto.h"#endif#ifdef HAVE_NETINET_IN_H#include	<netinet/in.h>#endif#include	<sys/socket.h>#ifdef HAVE_ARPA_INET_H#include	<arpa/inet.h>#endif#ifdef HAVE_MALLOC_H#include	<malloc.h>#endif#ifdef WIN32#include	<process.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;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 lrad_randctx lrad_rand_pool;	/* across multiple calls */static volatile int lrad_rand_index = -1;static unsigned int salt_offset = 0;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"};#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){	MD5_CTX context;        int             i;	MD5Init(&context);	MD5Update(&context, vector, AUTH_VECTOR_LEN);	MD5Update(&context, secret, strlen(secret));	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){	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);	MD5Init(&context);	MD5Update(&context, secret, strlen(secret));	old = context;	/*	 *	Do first pass.	 */	MD5Update(&context, vector, AUTH_PASS_LEN);	for (n = 0; n < len; n += AUTH_PASS_LEN) {		if (n > 0) {			context = old;			MD5Update(&context,				       passwd + n - AUTH_PASS_LEN,				       AUTH_PASS_LEN);		}		MD5Final(digest, &context);		for (i = 0; i < AUTH_PASS_LEN; i++) {			passwd[i + n] ^= digest[i];		}	}	memcpy(output, passwd, len);}static void make_tunnel_passwd(uint8_t *output, int *outlen,			       const uint8_t *input, int inlen, int room,			       const char *secret, const uint8_t *vector){	MD5_CTX context, old;	uint8_t	digest[AUTH_VECTOR_LEN];	uint8_t passwd[MAX_STRING_LEN + AUTH_VECTOR_LEN];	int	i, n;	int	len;	/*	 *	Account for 2 bytes of the salt, and round the room	 *	available down to the nearest multiple of 16.  Then,	 *	subtract one from that to account for the length byte,	 *	and the resulting number is the upper bound on the data	 *	to copy.	 *	 *	We could short-cut this calculation just be forcing	 *	inlen to be no more than 239.  It would work for all	 *	VSA's, as we don't pack multiple VSA's into one	 *	attribute.	 *	 *	However, this calculation is more general, if a little	 *	complex.  And it will work in the future for all possible	 *	kinds of weird attribute packing.	 */	room -= 2;	room -= (room & 0x0f);	room--;	if (inlen > room) inlen = room;	/*	 *	Length of the encrypted data is password length plus	 *	one byte for the length of the password.	 */	len = inlen + 1;	if ((len & 0x0f) != 0) {		len += 0x0f;		len &= ~0x0f;	}	*outlen = len + 2;	/* account for the salt */	/*	 *	Copy the password over.	 */	memcpy(passwd + 3, input, inlen);	memset(passwd + 3 + inlen, 0, sizeof(passwd) - 3 - inlen);	/*	 *	Generate salt.  The RFC's say:	 *	 *	The high bit of salt[0] must be set, each salt in a	 *	packet should be unique, and they should be random	 *	 *	So, we set the high bit, add in a counter, and then	 *	add in some CSPRNG data.  should be OK..	 */	passwd[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) |		     (lrad_rand() & 0x07));	passwd[1] = lrad_rand();	passwd[2] = inlen;	/* length of the password string */	MD5Init(&context);	MD5Update(&context, secret, strlen(secret));	old = context;	MD5Update(&context, vector, AUTH_VECTOR_LEN);	MD5Update(&context, &passwd[0], 2);	for (n = 0; n < len; n += AUTH_PASS_LEN) {		if (n > 0) {			context = old;			MD5Update(&context,				       passwd + 2 + n - AUTH_PASS_LEN,				       AUTH_PASS_LEN);		}		MD5Final(digest, &context);		for (i = 0; i < AUTH_PASS_LEN; i++) {			passwd[i + 2 + n] ^= digest[i];		}	}	memcpy(output, passwd, len + 2);}/* *	Parse a data structure into a RADIUS attribute. */int rad_vp2attr(const RADIUS_PACKET *packet, const RADIUS_PACKET *original,		const char *secret, const VALUE_PAIR *vp, uint8_t *ptr){	int		vendorcode;	int		offset, len, total_length;	uint32_t	lvalue;	uint8_t		*length_ptr, *vsa_length_ptr;	const uint8_t	*data = NULL;	uint8_t		array[4];	vendorcode = total_length = 0;	length_ptr = vsa_length_ptr = NULL;		/*	 *	For interoperability, always put vendor attributes	 *	into their own VSA.	 */	if ((vendorcode = VENDOR(vp->attribute)) != 0) {		/*		 *	Build a VSA header.		 */		*ptr++ = PW_VENDOR_SPECIFIC;		vsa_length_ptr = ptr;		*ptr++ = 6;		lvalue = htonl(vendorcode);		memcpy(ptr, &lvalue, 4);		ptr += 4;		total_length += 6;				if (vendorcode == VENDORPEC_USR) {			lvalue = htonl(vp->attribute & 0xFFFF);			memcpy(ptr, &lvalue, 4);						length_ptr = vsa_length_ptr;						total_length += 4;			*length_ptr  += 4;			ptr          += 4;						/*			 *	We don't have two different lengths.			 */			vsa_length_ptr = NULL;					} else if (vendorcode == VENDORPEC_LUCENT) {			/*			 *	16-bit attribute, 8-bit length			 */			*ptr++ = ((vp->attribute >> 8) & 0xFF);			*ptr++ = (vp->attribute & 0xFF);			length_ptr = ptr;			*vsa_length_ptr += 3;			*ptr++ = 3;			total_length += 3;		} else if (vendorcode == VENDORPEC_STARENT) {			/*			 *	16-bit attribute, 16-bit length			 *	with the upper 8 bits of the length			 *	always zero!			 */			*ptr++ = ((vp->attribute >> 8) & 0xFF);			*ptr++ = (vp->attribute & 0xFF);			*ptr++ = 0;			length_ptr = ptr;			*vsa_length_ptr += 4;			*ptr++ = 4;			total_length += 4;		} else {			/*			 *	All other VSA's are encoded the same			 *	as RFC attributes.			 */			*vsa_length_ptr += 2;			goto rfc;		}	} else {	rfc:		/*		 *	All other attributes are encoded as		 *	per the RFC.		 */		*ptr++ = (vp->attribute & 0xFF);		length_ptr = ptr;		*ptr++ = 2;		total_length += 2;	}	offset = 0;	if (vp->flags.has_tag) {		if (TAG_VALID(vp->flags.tag)) {			ptr[0] = vp->flags.tag & 0xff;			offset = 1;	    		} else if (vp->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) {			/*			 *	Tunnel passwords REQUIRE a tag, even			 *	if don't have a valid tag.			 */			ptr[0] = 0;			offset = 1;		} /* else don't write a tag */	} /* else the attribute doesn't have a tag */		/*	 *	Set up the default sources for the data.	 */	data = vp->strvalue;	len = vp->length;	/*	 *	Encrypted passwords can't be very long.	 *	This check also ensures that the hashed version	 *	of the password + attribute header fits into one	 *	attribute.	 *	 *	FIXME: Print a warning message if it's too long?	 */	if (vp->flags.encrypt && (len > MAX_PASS_LEN)) {		len = MAX_PASS_LEN;	}	switch(vp->type) {	case PW_TYPE_STRING:	case PW_TYPE_OCTETS:	case PW_TYPE_IFID:	case PW_TYPE_IPV6ADDR:	case PW_TYPE_IPV6PREFIX:	case PW_TYPE_ABINARY:		/* nothing more to do */		break;				case PW_TYPE_INTEGER:		len = 4;	/* just in case */		lvalue = htonl(vp->lvalue);		memcpy(array, &lvalue, sizeof(lvalue));		/*		 *	Perhaps discard the first octet.		 */		data = &array[offset];		len -= offset;		break;				case PW_TYPE_IPADDR:		data = (const uint8_t *) &vp->lvalue;		len = 4;	/* just in case */		break;		/*		 *  There are no tagged date attributes.		 */	case PW_TYPE_DATE:		lvalue = htonl(vp->lvalue);		data = (const uint8_t *) &lvalue;		len = 4;	/* just in case */		break;	default:		/* unknown type: ignore it */		librad_log("ERROR: Unknown attribute type %d", vp->type);		return -1;	}	/*	 *	Bound the data to 255 bytes.	 */	if (len + offset + total_length > 255) {		len = 255 - offset - total_length;	}		/*	 *	Encrypt the various password styles	 *	 *	Attributes with encrypted values MUST be less than	 *	128 bytes long.	 */	switch (vp->flags.encrypt) {	case FLAG_ENCRYPT_USER_PASSWORD:		make_passwd(ptr + offset, &len,			    data, len,			    secret, packet->vector);		break;			case FLAG_ENCRYPT_TUNNEL_PASSWORD:		if (!original) {			librad_log("ERROR: No request packet, cannot encrypt %s attribute in the vp.", vp->name);			return -1;		}		/*		 *	Check if 255 - offset - total_length is less		 *	than 18.  If so, we can't fit the data into		 *	the available space, and we discard the		 *	attribute.		 *		 *	This is ONLY a problem if we have multiple VSA's		 *	in one Vendor-Specific, though.		 */		if ((255 - offset - total_length) < 18) return 0;		/*		 *	Can't make the password, suppress it.		 */		make_tunnel_passwd(ptr + offset, &len,				   data, len, 255 - offset - total_length,				   secret, original->vector);		break;		/*		 *	The code above ensures that this attribute		 *	always fits.		 */	case FLAG_ENCRYPT_ASCEND_SECRET:		make_secret(ptr + offset, packet->vector,			    secret, data);		len = AUTH_VECTOR_LEN;		break;			default:		/*		 *	Just copy the data over		 */		memcpy(ptr + offset, data, len);		break;	} /* switch over encryption flags */	/*	 *	Account for the tag (if any).	 */	len += offset;	/*	 *	RFC 2865 section 5 says that zero-length attributes	 *	MUST NOT be sent.	 */	if (len == 0) return 0;	/*	 *	Update the various lengths.	 */	*length_ptr += len;	if (vsa_length_ptr) *vsa_length_ptr += len;	ptr += len;	total_length += len;	return total_length;	/* of attribute */}/* *	Encode a packet. */int rad_encode(RADIUS_PACKET *packet, const RADIUS_PACKET *original,	       const char *secret){	radius_packet_t	*hdr;	uint8_t	        *ptr;	uint16_t	total_length;	int		len;	VALUE_PAIR	*reply;		/*	 *	For simplicity in the following logic, we allow	 *	the attributes to "overflow" the 4k maximum	 *	RADIUS packet size, by one attribute.	 *	 *	It's uint32_t, for alignment purposes.	 */	uint32_t	data[(MAX_PACKET_LEN + 256) / 4];	/*	 *	Double-check some things based on packet code.	 */	switch (packet->code) {	case PW_AUTHENTICATION_ACK:	case PW_AUTHENTICATION_REJECT:	case PW_ACCESS_CHALLENGE:		if (!original) {			librad_log("ERROR: Cannot sign response packet without a request packet.");			return -1;		}		break;				/*		 *	These packet vectors start off as all zero.		 */	case PW_ACCOUNTING_REQUEST:	case PW_DISCONNECT_REQUEST:	case PW_COA_REQUEST:		memset(packet->vector, 0, sizeof(packet->vector));		break;			default:		break;	}			/*	 *	Use memory on the stack, until we know how	 *	large the packet will be.	 */	hdr = (radius_packet_t *) data;		/*	 *	Build standard header	 */	hdr->code = packet->code;

⌨️ 快捷键说明

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