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

📄 ttls.c

📁 radius服务器
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * rlm_eap_ttls.c  contains the interfaces that are called from eap * * Version:     $Id: ttls.c,v 1.17 2004/04/19 20:21:19 aland Exp $ * *   This program is free software; you can redistribute it and/or modify *   it under the terms of the GNU General Public License as published by *   the Free Software Foundation; either version 2 of the License, or *   (at your option) any later version. * *   This program 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 General Public License for more details. * *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * *   Copyright 2003 Alan DeKok <aland@freeradius.org> */#include "eap_tls.h"#include "eap_ttls.h"/* *    0                   1                   2                   3 *    0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *   |                           AVP Code                            | *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *   |V M r r r r r r|                  AVP Length                   | *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *   |                        Vendor-ID (opt)                        | *   +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ *   |    Data ... *   +-+-+-+-+-+-+-+-+ *//* *	Verify that the diameter packet is valid. */static int diameter_verify(const uint8_t *data, unsigned int data_len){	uint32_t attr;	uint32_t length;	unsigned int offset;	unsigned int data_left = data_len;	while (data_left > 0) {		rad_assert(data_left <= data_len);		memcpy(&attr, data, sizeof(attr));		data += 4;		attr = ntohl(attr);		if (attr > 255) {			DEBUG2("  rlm_eap_ttls:  Non-RADIUS attribute in tunneled authentication is not supported");			return 0;		}		memcpy(&length, data , sizeof(length));		data += 4;		length = ntohl(length);		/*		 *	A "vendor" flag, with a vendor ID of zero,		 *	is equivalent to no vendor.  This is stupid.		 */		offset = 8;		if ((length & (1 << 31)) != 0) {			int attribute;			uint32_t vendor;			DICT_ATTR *da;			memcpy(&vendor, data, sizeof(vendor));			vendor = ntohl(vendor);			if (vendor > 65535) {				DEBUG2("  rlm_eap_ttls: Vendor codes larger than 65535 are not supported");				return 0;			}			attribute = (vendor << 16) | attr;			da = dict_attrbyvalue(attribute);			/*			 *	SHOULD check ((length & (1 << 30)) != 0)			 *	for the mandatory bit.			 */			if (!da) {				DEBUG2("  rlm_eap_ttls: Fatal! Vendor %u, Attribute %u was not found in our dictionary. ",				       vendor, attr);				return 0;			}			data += 4; /* skip the vendor field */			offset += 4; /* offset to value field */		}		/*		 *	Ignore the M bit.  We support all RADIUS attributes...		 */		/*		 *	Get the length.  If it's too big, die.		 */		length &= 0x00ffffff;		/*		 *	Too short or too long is bad.		 *		 *	FIXME: EAP-Message		 */		if (length < offset) {			DEBUG2("  rlm_eap_ttls: Tunneled attribute %d is too short (%d)to contain anything useful.", attr, length);			return 0;		}		if (length > (MAX_STRING_LEN + 8)) {			DEBUG2("  rlm_eap_ttls: Tunneled attribute %d is too long (%d) to pack into a RADIUS attribute.", attr, length);			return 0;		}		    		if (length > data_left) {			DEBUG2("  rlm_eap_ttls: Tunneled attribute %d is longer than room left in the packet (%d > %d).", attr, length, data_left);			return 0;		}		/*		 *	Check for broken implementations, which don't		 *	pad the AVP to a 4-octet boundary.		 */		if (data_left == length) break;		/*		 *	The length does NOT include the padding, so		 *	we've got to account for it here by rounding up		 *	to the nearest 4-byte boundary.		 */		length += 0x03;		length &= ~0x03;		/*		 *	If the rest of the diameter packet is larger than		 *	this attribute, continue.		 *		 *	Otherwise, if the attribute over-flows the end		 *	of the packet, die.		 */		if (data_left < length) {			DEBUG2("  rlm_eap_ttls: ERROR! Diameter attribute overflows packet!");			return 0;		}			/*		 *	Check again for equality, now that we're padded		 *	length to a multiple of 4 octets.		 */		if (data_left == length) break;		/*		 *	data_left > length, continue.		 */		data_left -= length;		data += length - offset;	}	/*	 *	We got this far.  It looks OK.	 */	return 1;}/* *	Convert diameter attributes to our VALUE_PAIR's */static VALUE_PAIR *diameter2vp(SSL *ssl,			       const uint8_t *data, unsigned int data_len){	uint32_t	attr;	uint32_t	length;	unsigned int	offset;	int		size;	unsigned int	data_left = data_len;	VALUE_PAIR	*first = NULL;	VALUE_PAIR	**last = &first;	VALUE_PAIR	*vp;	while (data_left > 0) {		rad_assert(data_left <= data_len);		memcpy(&attr, data, sizeof(attr));		data += 4;		attr = ntohl(attr);		memcpy(&length, data, sizeof(length));		data += 4;		length = ntohl(length);		/*		 *	Ignore the M bit.  We support all RADIUS attributes...		 */		/*		 *	A "vendor" flag, with a vendor ID of zero,		 *	is equivalent to no vendor.  This is stupid.		 */		offset = 8;		if ((length & (1 << 31)) != 0) {			uint32_t vendor;			memcpy(&vendor, data, sizeof(vendor));			vendor = ntohl(vendor);			attr |= (vendor << 16);			data += 4; /* skip the vendor field, it's zero */			offset += 4; /* offset to value field */		}		/*		 *	Get the length.		 */		length &= 0x00ffffff;		/*		 *	diameter code + length, and it must fit in		 *	a VALUE_PAIR.		 */		rad_assert(length <= (offset + MAX_STRING_LEN));		/*		 *	Get the size of the value portion of the		 *	attribute.		 */		size = length - offset;		/*		 *	Create it.		 */		vp = paircreate(attr, PW_TYPE_OCTETS);		if (!vp) {			DEBUG2("  rlm_eap_ttls: Failure in creating VP");			pairfree(&first);			return NULL;		}		/*		 *	If it's a type from our dictionary, then		 *	we need to put the data in a relevant place.		 */		switch (vp->type) {		case PW_TYPE_INTEGER:		case PW_TYPE_DATE:			if (size != vp->length) {				DEBUG2("  rlm_eap_ttls: Invalid length attribute %d",				       attr);				pairfree(&first);				return NULL;			}			memcpy(&vp->lvalue, data, vp->length);						/*			 *	Stored in host byte order: change it.			 */			vp->lvalue = ntohl(vp->lvalue);			break;					case PW_TYPE_IPADDR:			if (size != vp->length) {				DEBUG2("  rlm_eap_ttls: Invalid length attribute %d",				       attr);				pairfree(&first);				return NULL;			}		  memcpy(&vp->lvalue, data, vp->length);		  		  /*		   *	Stored in network byte order: don't change it.		   */		  break;		  /*		   *	String, octet, etc.  Copy the data from the		   *	value field over verbatim.		   *		   *	FIXME: Ipv6 attributes ?		   *		   */		default:			vp->length = size;			memcpy(vp->strvalue, data, vp->length);			break;		}		/*		 *	User-Password is NUL padded to a multiple		 *	of 16 bytes.  Let's chop it to something		 *	more reasonable.		 *		 *	NOTE: This means that the User-Password		 *	attribute CANNOT EVER have embedded zeros in it!		 */		switch (vp->attribute) {		case PW_USER_PASSWORD:			rad_assert(vp->length <= 128); /* RFC requirements */			/*			 *	If the password is exactly 16 octets,			 *	it won't be zero-terminated.			 */			vp->strvalue[vp->length] = '\0';			vp->length = strlen(vp->strvalue);			break;			/*			 *	Ensure that the client is using the			 *	correct challenge.  This weirdness is			 *	to protect against against replay			 *	attacks, where anyone observing the			 *	CHAP exchange could pose as that user,			 *	by simply choosing to use the same			 *	challenge.			 *			 *	By using a challenge based on			 *	information from the current session,			 *	we can guarantee that the client is			 *	not *choosing* a challenge.			 *			 *	We're a little forgiving in that we			 *	have loose checks on the length, and			 *	we do NOT check the Id (first octet of			 *	the response to the challenge)			 *			 *	But if the client gets the challenge correct,			 *	we're not too worried about the Id.			 */		case PW_CHAP_CHALLENGE:		case PW_MSCHAP_CHALLENGE:			if ((vp->length < 8) ||			    (vp->length > 16)) {				DEBUG2("  TTLS: Tunneled challenge has invalid length");				pairfree(&first);				return NULL;			} else {				int i;				uint8_t	challenge[16];				eapttls_gen_challenge(ssl, challenge,						      sizeof(challenge));				for (i = 0; i < vp->length; i++) {					if (challenge[i] != vp->strvalue[i]) {						DEBUG2("  TTLS: Tunneled challenge is incorrect");						pairfree(&first);						return NULL;					}				}			}			break;		default:			break;		} /* switch over checking/re-writing of attributes. */		/*		 *	Update the list.		 */		*last = vp;		last = &(vp->next);		/*		 *	Catch non-aligned attributes.		 */		if (data_left == length) break;		/*		 *	The length does NOT include the padding, so		 *	we've got to account for it here by rounding up		 *	to the nearest 4-byte boundary.		 */		length += 0x03;		length &= ~0x03;		rad_assert(data_left >= length);		data_left -= length;		data += length - offset; /* already updated */	}	/*	 *	We got this far.  It looks OK.	 */	return first;}/* *	Convert VALUE_PAIR's to diameter attributes, and write them *	to an SSL session. * *	The ONLY VALUE_PAIR's which may be passed to this function *	are ones which can go inside of a RADIUS (i.e. diameter) *	packet.  So no server-configuration attributes, or the like. */static int vp2diameter(tls_session_t *tls_session, VALUE_PAIR *first){	/*	 *	RADIUS packets are no more than 4k in size, so if	 *	we've got more than 4k of data to write, it's very	 *	bad.	 */	uint8_t		buffer[4096];	uint8_t		*p;	uint32_t	attr;	uint32_t	length;	uint32_t	vendor;	size_t		total;	VALUE_PAIR	*vp;	p = buffer;	total = 0;	for (vp = first; vp != NULL; vp = vp->next) {		/*		 *	Too much data: die.		 */		if ((total + vp->length + 12) >= sizeof(buffer)) {			DEBUG2("  TTLS output buffer is full!");			return 0;		}		/*		 *	Hmm... we don't group multiple EAP-Messages		 *	together.  Maybe we should...		 */		/*		 *	Length is no more than 253, due to RADIUS		 *	issues.		 */		length = vp->length;		vendor = (vp->attribute >> 16) & 0xffff;		if (vendor != 0) {			attr = vp->attribute & 0xffff;			length |= (1 << 31);		} else {			attr = vp->attribute;		}		/*		 *	Hmm... set the M bit for all attributes?		 */		length |= (1 << 30);		attr = ntohl(attr);		memcpy(p, &attr, sizeof(attr));		p += 4;		total += 4;		length += 8;	/* includes 8 bytes of attr & length */		if (vendor != 0) {			length += 4; /* include 4 bytes of vendor */			length = ntohl(length);			memcpy(p, &length, sizeof(length));			p += 4;			total += 4;			vendor = ntohl(vendor);			memcpy(p, &vendor, sizeof(vendor));			p += 4;			total += 4;		} else {			length = ntohl(length);			memcpy(p, &length, sizeof(length));			p += 4;			total += 4;		}		switch (vp->type) {		case PW_TYPE_INTEGER:		case PW_TYPE_DATE:			attr = ntohl(vp->lvalue); /* stored in host order */			memcpy(p, &attr, sizeof(attr));			length = 4;			break;		case PW_TYPE_IPADDR:			attr = vp->lvalue; /* stored in network order */			memcpy(p, &attr, sizeof(attr));			length = 4;			break;		case PW_TYPE_STRING:		case PW_TYPE_OCTETS:		default:			memcpy(p, vp->strvalue, vp->length);			length = vp->length;			break;		}		/*		 *	Skip to the end of the data.		 */		p += length;		total += length;		/*		 *	Align the data to a multiple of 4 bytes.		 */		if ((total & 0x03) != 0) {			unsigned int i;			length = 4 - (total & 0x03);			for (i = 0; i < length; i++) {				*p = '\0';				p++;				total++;			}		}	} /* loop over the VP's to write. */	/*	 *	Write the data in the buffer to the SSL session.	 */	if (total > 0) {#ifndef NDEBUG		unsigned int i;		if (debug_flag > 2) {			for (i = 0; i < total; i++) {				if ((i & 0x0f) == 0) printf("  TTLS tunnel data out %04x: ", i);				printf("%02x ", buffer[i]);				if ((i & 0x0f) == 0x0f) printf("\n");			}			if ((total & 0x0f) != 0) printf("\n");		}#endif		record_plus(&tls_session->clean_in, buffer, total);		/*		 *	FIXME: Check the return code.		 */		tls_handshake_send(tls_session);		record_init(&tls_session->clean_in);	}	/*	 *	Everything's OK.	 */	return 1;}/* *	Use a reply packet to determine what to do. */static int process_reply(EAP_HANDLER *handler, tls_session_t *tls_session,			 REQUEST *request, RADIUS_PACKET *reply){	int rcode = RLM_MODULE_REJECT;	VALUE_PAIR *vp;	ttls_tunnel_t *t = tls_session->opaque;	handler = handler;	/* -Wunused */	/*	 *	If the response packet was Access-Accept, then	 *	we're OK.  If not, die horribly.	 *	 *	FIXME: Take MS-CHAP2-Success attribute, and	 *	tunnel it back to the client, to authenticate	 *	ourselves to the client.	 *	 *	FIXME: If we have an Access-Challenge, then	 *	the Reply-Message is tunneled back to the client.	 *	 *	FIXME: If we have an EAP-Message, then that message	 *	must be tunneled back to the client.	 *	 *	FIXME: If we have an Access-Challenge with a State	 *	attribute, then do we tunnel that to the client, or	 *	keep track of it ourselves?	 *	 *	FIXME: EAP-Messages can only start with 'identity',	 *	NOT 'eap start', so we should check for that....	 */	switch (reply->code) {	case PW_AUTHENTICATION_ACK:		DEBUG2("  TTLS: Got tunneled Access-Accept");		rcode = RLM_MODULE_OK;		/*		 *	MS-CHAP2-Success means that we do NOT return		 *	an Access-Accept, but instead tunnel that		 *	attribute to the client, and keep going with		 *	the TTLS session.  Once the client accepts		 *	our identity, it will respond with an empty		 *	packet, and we will send EAP-Success.		 */		vp = NULL;		pairmove2(&vp, &reply->vps, PW_MSCHAP2_SUCCESS);		if (vp) {#if 1			/*			 *	FIXME: Tunneling MS-CHAP2-Success causes			 *	the only client we have access to, to die.			 *			 *	We don't want that...			 */			pairfree(&vp);#else			DEBUG2("  TTLS: Got MS-CHAP2-Success, tunneling it to the client in a challenge.");			rcode = RLM_MODULE_HANDLED;			t->authenticated = TRUE;#endif		} else { /* no MS-CHAP2-Success */			/*			 *	Can only have EAP-Message if there's			 *	no MS-CHAP2-Success.  (FIXME: EAP-MSCHAP?)			 *			 *	We also do NOT tunnel the EAP-Success			 *	attribute back to the client, as the client			 *	can figure it out, from the non-tunneled			 *	EAP-Success packet.			 */			pairmove2(&vp, &reply->vps, PW_EAP_MESSAGE);

⌨️ 快捷键说明

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