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

📄 radius.c

📁 radius服务器
💻 C
📖 第 1 页 / 共 4 页
字号:
		  if (!packet->data) {			  librad_log("Out of memory");			  return -1;		  }		  memcpy(packet->data, data, packet->data_len);		  hdr = (radius_packet_t *) packet->data;		  total_length = htons(total_length);		  memcpy(hdr->length, &total_length, sizeof(u_short));		  /*		   *	If this is not an authentication request, we		   *	need to calculate the md5 hash over the entire packet		   *	and put it in the vector.		   */		  secretlen = strlen(secret);		  /*		   *	If there's a Message-Authenticator, update it		   *	now, BEFORE updating the authentication vector.		   */		  if (msg_auth_offset) {			  uint8_t calc_auth_vector[AUTH_VECTOR_LEN];			  switch (packet->code) {			  default:				  break;			  case PW_AUTHENTICATION_ACK:			  case PW_AUTHENTICATION_REJECT:			  case PW_ACCESS_CHALLENGE:				  /* this was checked above */				  memcpy(hdr->vector, original->vector,					 AUTH_VECTOR_LEN);				  break;			  }			  /*			   *	Set the authentication vector to zero,			   *	calculate the signature, and put it			   *	into the Message-Authenticator			   *	attribute.			   */			  memset(packet->data + msg_auth_offset + 2,				 0, AUTH_VECTOR_LEN);			  lrad_hmac_md5(packet->data, packet->data_len,					secret, secretlen, calc_auth_vector);			  memcpy(packet->data + msg_auth_offset + 2,				 calc_auth_vector, AUTH_VECTOR_LEN);			  /*			   *	Copy the original request vector back			   *	to the raw packet.			   */			  memcpy(hdr->vector, packet->vector, AUTH_VECTOR_LEN);		  }		  /*		   *	Switch over the packet code, deciding how to		   *	sign the packet.		   */		  switch (packet->code) {			  /*			   *	Request packets are not signed, bur			   *	have a random authentication vector.			   */		  case PW_AUTHENTICATION_REQUEST:		  case PW_STATUS_SERVER:			  break;			  /*			   *	Reply packets are signed with the			   *	authentication vector of the request.			   */		  default:		  	{				MD5_CTX	context;				MD5Init(&context);				MD5Update(&context, packet->data, packet->data_len);				MD5Update(&context, secret, strlen(secret));				MD5Final(digest, &context);				memcpy(hdr->vector, digest, AUTH_VECTOR_LEN);				memcpy(packet->vector, digest, AUTH_VECTOR_LEN);				break;			}		  } /* switch over packet codes */		  /*		   *	If packet->data points to data, then we print out		   *	the VP list again only for debugging.		   */	} else if (librad_debug) {	  	DEBUG("Re-sending %s of id %d to %s:%d\n", what, packet->id,		      ip_ntoa((char *)ip_buffer, packet->dst_ipaddr),		      packet->dst_port);		for (reply = packet->vps; reply; reply = reply->next) {			/* FIXME: ignore attributes > 0xff */			debug_pair(reply);		}	}	/*	 *	And send it on it's way.	 */	sa = (struct sockaddr_in *) &saremote;        memset ((char *) sa, '\0', sizeof (saremote));	sa->sin_family = AF_INET;	sa->sin_addr.s_addr = packet->dst_ipaddr;	sa->sin_port = htons(packet->dst_port);#ifndef WITH_UDPFROMTO	return sendto(packet->sockfd, packet->data, (int)packet->data_len, 0,		      (struct sockaddr *)&saremote, sizeof(struct sockaddr_in));#else	{		struct sockaddr_in salocal;		memset ((char *) &salocal, '\0', sizeof (salocal));		salocal.sin_family = AF_INET;		salocal.sin_addr.s_addr = packet->src_ipaddr;				return sendfromto(packet->sockfd, packet->data, (int)packet->data_len, 0,				  (struct sockaddr *)&salocal,  sizeof(struct sockaddr_in),				  (struct sockaddr *)&saremote, sizeof(struct sockaddr_in));	}#endif}/* *	Validates the requesting client NAS.  Calculates the *	signature based on the clients private key. */static int calc_acctdigest(RADIUS_PACKET *packet, const char *secret){	u_char		digest[AUTH_VECTOR_LEN];	MD5_CTX		context;	/*	 *	Older clients have the authentication vector set to	 *	all zeros. Return `1' in that case.	 */	memset(digest, 0, sizeof(digest));	if (memcmp(packet->vector, digest, AUTH_VECTOR_LEN) == 0) {		packet->verified = 1;		return 1;	}	/*	 *	Zero out the auth_vector in the received packet.	 *	Then append the shared secret to the received packet,	 *	and calculate the MD5 sum. This must be the same	 *	as the original MD5 sum (packet->vector).	 */	memset(packet->data + 4, 0, AUTH_VECTOR_LEN);	/*	 *  MD5(packet + secret);	 */	MD5Init(&context);	MD5Update(&context, packet->data, packet->data_len);	MD5Update(&context, secret, strlen(secret));	MD5Final(digest, &context);	/*	 *	Return 0 if OK, 2 if not OK.	 */	packet->verified =	memcmp(digest, packet->vector, AUTH_VECTOR_LEN) ? 2 : 0;	return packet->verified;}/* *	Validates the requesting client NAS.  Calculates the *	signature based on the clients private key. */static int calc_replydigest(RADIUS_PACKET *packet, RADIUS_PACKET *original,			    const char *secret){	uint8_t		calc_digest[AUTH_VECTOR_LEN];	MD5_CTX		context;	/*	 *	Very bad!	 */	if (original == NULL) {		return 3;	}	/*	 *  Copy the original vector in place.	 */	memcpy(packet->data + 4, original->vector, AUTH_VECTOR_LEN);	/*	 *  MD5(packet + secret);	 */	MD5Init(&context);	MD5Update(&context, packet->data, packet->data_len);	MD5Update(&context, secret, strlen(secret));	MD5Final(calc_digest, &context);	/*	 *  Copy the packet's vector back to the packet.	 */	memcpy(packet->data + 4, packet->vector, AUTH_VECTOR_LEN);	/*	 *	Return 0 if OK, 2 if not OK.	 */	packet->verified =		memcmp(packet->vector, calc_digest, AUTH_VECTOR_LEN) ? 2 : 0;	return packet->verified;}/* *	Receive UDP client requests, and fill in *	the basics of a RADIUS_PACKET structure. */RADIUS_PACKET *rad_recv(int fd){	RADIUS_PACKET		*packet;	struct sockaddr_in	saremote;	int			totallen;	socklen_t		salen;	uint8_t			*attr;	int			count;	radius_packet_t		*hdr;	char			host_ipaddr[16];	int			seen_eap;	uint8_t			data[MAX_PACKET_LEN];	int			num_attributes;	/*	 *	Allocate the new request data structure	 */	if ((packet = malloc(sizeof(RADIUS_PACKET))) == NULL) {		librad_log("out of memory");		return NULL;	}	memset(packet, 0, sizeof(RADIUS_PACKET));	/*	 *	Receive the packet.	 */	salen = sizeof(saremote);	memset(&saremote, 0, sizeof(saremote));#ifndef WITH_UDPFROMTO	packet->data_len = recvfrom(fd, data, sizeof(data),				    0, (struct sockaddr *)&saremote, &salen);	packet->dst_ipaddr = htonl(INADDR_ANY); /* i.e. unknown */#else	{		socklen_t		salen_local;		struct sockaddr_in	salocal;		salen_local = sizeof(salocal);		memset(&salocal, 0, sizeof(salocal));		packet->data_len = recvfromto(fd, data, sizeof(data), 0,					      (struct sockaddr *)&saremote, &salen,					      (struct sockaddr *)&salocal, &salen_local);		packet->dst_ipaddr = salocal.sin_addr.s_addr;	}#endif	/*	 *	Check for socket errors.	 */	if (packet->data_len < 0) {		librad_log("Error receiving packet: %s", strerror(errno));		free(packet);		return NULL;	}	/*	 *	Fill IP header fields.  We need these for the error	 *	messages which may come later.	 */	packet->sockfd = fd;	packet->src_ipaddr = saremote.sin_addr.s_addr;	packet->src_port = ntohs(saremote.sin_port);	/*	 *	FIXME: Do even more filtering by only permitting	 *	certain IP's.  The problem is that we don't know	 *	how to do this properly for all possible clients...	 */	/*	 *	Explicitely set the VP list to empty.	 */	packet->vps = NULL;	/*	 *	Check for packets smaller than the packet header.	 *	 *	RFC 2865, Section 3., subsection 'length' says:	 *	 *	"The minimum length is 20 ..."	 */	if (packet->data_len < AUTH_HDR_LEN) {		librad_log("WARNING: Malformed RADIUS packet from host %s: too short (received %d < minimum %d)",			   ip_ntoa(host_ipaddr, packet->src_ipaddr),			   packet->data_len, AUTH_HDR_LEN);		free(packet);		return NULL;	}	/*	 *	RFC 2865, Section 3., subsection 'length' says:	 *	 *	" ... and maximum length is 4096."	 */	if (packet->data_len > MAX_PACKET_LEN) {		librad_log("WARNING: Malformed RADIUS packet from host %s: too long (received %d > maximum %d)",			   ip_ntoa(host_ipaddr, packet->src_ipaddr),			   packet->data_len, MAX_PACKET_LEN);		free(packet);		return NULL;	}	/*	 *	Check for packets with mismatched size.	 *	i.e. We've received 128 bytes, and the packet header	 *	says it's 256 bytes long.	 */	totallen = (data[2] << 8) | data[3];	hdr = (radius_packet_t *)data;	/*	 *	Code of 0 is not understood.	 *	Code of 16 or greate is not understood.	 */	if ((hdr->code == 0) ||	    (hdr->code >= 52)) {		librad_log("WARNING: Bad RADIUS packet from host %s: unknown packet code %d",			   ip_ntoa(host_ipaddr, packet->src_ipaddr),			   hdr->code);		free(packet);		return NULL;	}	/*	 *	Repeat the length checks.  This time, instead of	 *	looking at the data we received, look at the value	 *	of the 'length' field inside of the packet.	 *	 *	Check for packets smaller than the packet header.	 *	 *	RFC 2865, Section 3., subsection 'length' says:	 *	 *	"The minimum length is 20 ..."	 */	if (totallen < AUTH_HDR_LEN) {		librad_log("WARNING: Malformed RADIUS packet from host %s: too short (length %d < minimum %d)",			   ip_ntoa(host_ipaddr, packet->src_ipaddr),			   totallen, AUTH_HDR_LEN);		free(packet);		return NULL;	}	/*	 *	And again, for the value of the 'length' field.	 *	 *	RFC 2865, Section 3., subsection 'length' says:	 *	 *	" ... and maximum length is 4096."	 */	if (totallen > MAX_PACKET_LEN) {		librad_log("WARNING: Malformed RADIUS packet from host %s: too long (length %d > maximum %d)",			   ip_ntoa(host_ipaddr, packet->src_ipaddr),			   totallen, MAX_PACKET_LEN);		free(packet);		return NULL;	}	/*	 *	RFC 2865, Section 3., subsection 'length' says:	 *	 *	"If the packet is shorter than the Length field	 *	indicates, it MUST be silently discarded."	 *	 *	i.e. No response to the NAS.	 */	if (packet->data_len < totallen) {		librad_log("WARNING: Malformed RADIUS packet from host %s: received %d octets, packet length says %d",			   ip_ntoa(host_ipaddr, packet->src_ipaddr),			   packet->data_len, totallen);		free(packet);		return NULL;	}	/*	 *	RFC 2865, Section 3., subsection 'length' says:	 *	 *	"Octets outside the range of the Length field MUST be	 *	treated as padding and ignored on reception."	 */	if (packet->data_len > totallen) {		/*		 *	We're shortening the packet below, but just		 *	to be paranoid, zero out the extra data.		 */		memset(data + totallen, 0, packet->data_len - totallen);		packet->data_len = totallen;	}	/*	 *	Walk through the packet's attributes, ensuring that	 *	they add up EXACTLY to the size of the packet.	 *	 *	If they don't, then the attributes either under-fill	 *	or over-fill the packet.  Any parsing of the packet	 *	is impossible, and will result in unknown side effects.	 *	 *	This would ONLY happen with buggy RADIUS implementations,	 *	or with an intentional attack.  Either way, we do NOT want	 *	to be vulnerable to this problem.	 */	attr = hdr->data;	count = totallen - AUTH_HDR_LEN;	seen_eap = 0;	num_attributes = 0;	while (count > 0) {		/*		 *	Attribute number zero is NOT defined.		 */		if (attr[0] == 0) {			librad_log("WARNING: Malformed RADIUS packet from host %s: Invalid attribute 0",				   ip_ntoa(host_ipaddr, packet->src_ipaddr));			free(packet);			return NULL;		}		/*		 *	Attributes are at LEAST as long as the ID & length		 *	fields.  Anything shorter is an invalid attribute.		 */       		if (attr[1] < 2) {			librad_log("WARNING: Malformed RADIUS packet from host %s: attribute %d too short",				   ip_ntoa(host_ipaddr, packet->src_ipaddr),				   attr[0]);			free(packet);			return NULL;		}		/*		 *	Sanity check the attributes for length.		 */		switch (attr[0]) {		default:	/* don't do anything by default */			break;		case PW_EAP_MESSAGE:			seen_eap |= PW_EAP_MESSAGE;			break;		case PW_MESSAGE_AUTHENTICATOR:			if (attr[1] != 2 + AUTH_VECTOR_LEN) {				librad_log("WARNING: Malformed RADIUS packet from host %s: Message-Authenticator has invalid length %d",					   ip_ntoa(host_ipaddr, packet->src_ipaddr),					   attr[1] - 2);				free(packet);				return NULL;			}			seen_eap |= PW_MESSAGE_AUTHENTICATOR;			break;		case PW_VENDOR_SPECIFIC:			if (attr[1] <= 6) {				librad_log("WARNING: Malformed RADIUS packet from host %s: Vendor-Specific has invalid length %d",					   ip_ntoa(host_ipaddr, packet->src_ipaddr),					   attr[1] - 2);				free(packet);				return NULL;			}			/*			 *	Don't allow VSA's with vendor zero.			 */			if ((attr[2] == 0) && (attr[3] == 0) &&			    (attr[4] == 0) && (attr[5] == 0)) {				librad_log("WARNING: Malformed RADIUS packet from host %s: Vendor-Specific has vendor ID of zero",					   ip_ntoa(host_ipaddr, packet->src_ipaddr));				free(packet);				return NULL;			}			/*			 *	Don't look at the contents of VSA's,			 *	too many vendors have non-standard			 *	formats.			 */			break;		}		/*		 *	FIXME: Look up the base 255 attributes in the		 *	dictionary, and switch over their type.  For		 *	integer/date/ip, the attribute length SHOULD		 *	be 6.		 */		count -= attr[1];	/* grab the attribute length */		attr += attr[1];		num_attributes++;	/* seen one more attribute */	}	/*	 *	If the attributes add up to a packet, it's allowed.	 *	 *	If not, we complain, and throw the packet away.	 */	if (count != 0) {		librad_log("WARNING: Malformed RADIUS packet from host %s: packet attributes do NOT exactly fill the packet",			   ip_ntoa(host_ipaddr, packet->src_ipaddr));		free(packet);		return NULL;	}	/*	 *	If we're configured to look for a maximum number of	 *	attributes, and we've seen more than that maximum,	 *	then throw the packet away, as a possible DoS.	 */	if ((librad_max_attributes > 0) &&	    (num_attributes > librad_max_attributes)) {		librad_log("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",			   ip_ntoa(host_ipaddr, packet->src_ipaddr),			   num_attributes, librad_max_attributes);		free(packet);		return NULL;	}	/*	 * 	http://www.freeradius.org/rfc/rfc2869.html#EAP-Message	 *	 *	A packet with an EAP-Message attribute MUST also have	 *	a Message-Authenticator attribute.	 *	 *	A Message-Authenticator all by itself is OK, though.	 */	if (seen_eap &&	    (seen_eap != PW_MESSAGE_AUTHENTICATOR) &&

⌨️ 快捷键说明

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