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

📄 radius.c

📁 radius服务器
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * radius.c	Functions to send/receive radius packets. * * Version:	$Id: radius.c,v 1.125.2.1 2004/08/30 17:48:31 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA * * Copyright 2000-2003  The FreeRADIUS server project */static const char rcsid[] = "$Id: radius.c,v 1.125.2.1 2004/08/30 17:48:31 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 int lrad_pool_initialized = 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",  "CoF-Request",  "CoF-ACK",  "CoF-NAK",  "46",  "47",  "48",  "49",  "IP-Address-Allocate",  "IP-Address-Release"};/* *  Internal prototypes */static void make_secret(unsigned char *digest, uint8_t *vector,			const char *secret, char *value);/* *	Reply to the request.  Also attach *	reply attribute value pairs and any user message provided. */int rad_send(RADIUS_PACKET *packet, const RADIUS_PACKET *original,	     const char *secret){	VALUE_PAIR		*reply;	struct	sockaddr_in	saremote;	struct	sockaddr_in	*sa;	const char		*what;	uint8_t			ip_buffer[16];	/*	 *	Maybe it's a fake packet.  Don't send it.	 */	if (!packet || (packet->sockfd < 0)) {		return 0;	}	if ((packet->code > 0) && (packet->code < 52)) {		what = packet_codes[packet->code];	} else {		what = "Reply";	}	/*	 *  First time through, allocate room for the packet	 */	if (!packet->data) {		  radius_packet_t	*hdr;		  uint32_t		lvalue;		  uint8_t		*ptr, *length_ptr, *vsa_length_ptr;		  uint8_t		digest[16];		  int			secretlen;		  int			vendorcode, vendorpec;		  u_short		total_length;		  int			len, allowed;		  int			msg_auth_offset = 0;		  /*		   *	For simplicity in the following logic, we allow		   *	the attributes to "overflow" the 4k maximum		   *	RADIUS packet size, by one attribute.		   */		  uint8_t		data[MAX_PACKET_LEN + 256];		  /*		   *	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;		  hdr->id = packet->id;		  /*		   *	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:			  memset(packet->vector, 0, sizeof(packet->vector));			  break;		  default:			  break;		  }		  memcpy(hdr->vector, packet->vector, sizeof(hdr->vector));		  DEBUG("Sending %s of id %d to %s:%d\n",			what, packet->id,			ip_ntoa((char *)ip_buffer, packet->dst_ipaddr),			packet->dst_port);		  total_length = AUTH_HDR_LEN;		  /*		   *	Load up the configuration values for the user		   */		  ptr = hdr->data;		  vendorcode = 0;		  vendorpec = 0;		  vsa_length_ptr = NULL;		  /*		   *	Loop over the reply attributes for the packet.		   */		  for (reply = packet->vps; reply; reply = reply->next) {			  /*			   *	Ignore non-wire attributes			   */			  if ((VENDOR(reply->attribute) == 0) &&			      ((reply->attribute & 0xFFFF) > 0xff)) {				  continue;			  }			  /*			   *	Check that the packet is no more than			   *	4k in size, AFTER over-flowing the 4k			   *	boundary.  Note that the 'data'			   *	buffer, above, is one attribute longer			   *	than necessary, in order to permit			   *	this overflow.			   */			  if (total_length > MAX_PACKET_LEN) {				  librad_log("ERROR: Too many attributes for packet, result is larger than RFC maximum of 4k");				  return -1;			  }			  /*			   *	Set the Message-Authenticator to the			   *	correct length and initial value.			   */			  if (reply->attribute == PW_MESSAGE_AUTHENTICATOR) {				  reply->length = AUTH_VECTOR_LEN;				  memset(reply->strvalue, 0, AUTH_VECTOR_LEN);				  msg_auth_offset = total_length;			  }			  /*			   *	Print out ONLY the attributes which			   *	we're sending over the wire, and print			   *	them out BEFORE they're encrypted.			   */			  debug_pair(reply);			  /*			   *	We have a different vendor.  Re-set			   *	the vendor codes.			   */			  if (vendorcode != VENDOR(reply->attribute)) {				  vendorcode = 0;				  vendorpec = 0;				  vsa_length_ptr = NULL;			  }			  /*			   *	If the Vendor-Specific attribute is getting			   *	full, then create a new VSA attribute			   *			   *	FIXME: Multiple VSA's per Vendor-Specific			   *	SHOULD be configurable.  When that's done,			   *	the (1), below, can be changed to point to			   *	a configuration variable which is set TRUE			   *	if the NAS cannot understand multiple VSA's			   *	per Vendor-Specific			   */			  if ((1) || /* ALWAYS create a new Vendor-Specific */			      (vsa_length_ptr &&			       (reply->length + *vsa_length_ptr) >= MAX_STRING_LEN)) {				  vendorcode = 0;				  vendorpec = 0;				  vsa_length_ptr = NULL;			  }			  /*			   *	Maybe we have the start of a set of			   *	(possibly many) VSA attributes from			   *	one vendor.  Set a global VSA wrapper			   */			  if ((vendorcode == 0) &&			      ((vendorcode = VENDOR(reply->attribute)) != 0)) {				  vendorpec  = dict_vendorpec(vendorcode);				  /*				   *	This is a potentially bad error...				   *	we can't find the vendor ID!				   */				  if (vendorpec == 0) {					  /* FIXME: log an error */					  continue;				  }				  /*				   *	Build a VSA header.				   */				  *ptr++ = PW_VENDOR_SPECIFIC;				  vsa_length_ptr = ptr;				  *ptr++ = 6;				  lvalue = htonl(vendorpec);				  memcpy(ptr, &lvalue, 4);				  ptr += 4;				  total_length += 6;			  }			  if (vendorpec == VENDORPEC_USR) {				  lvalue = htonl(reply->attribute & 0xFFFF);				  memcpy(ptr, &lvalue, 4);				  length_ptr = vsa_length_ptr;				  total_length += 4;				  *length_ptr  += 4;				  ptr          += 4;				  /*				   *	Each USR-style attribute gets				   *	it's own VSA wrapper, so we				   *	re-set the vendor specific				   *	information.				   */				  vendorcode = 0;				  vendorpec = 0;				  vsa_length_ptr = NULL;			  } else {				  /*				   *	All other attributes are as				   *	per the RFC spec.				   */				  *ptr++ = (reply->attribute & 0xFF);				  length_ptr = ptr;				  if (vsa_length_ptr) *vsa_length_ptr += 2;				  *ptr++ = 2;				  total_length += 2;			  }			  switch(reply->type) {				  /*				   *	Ascend binary attributes are				   *	stored internally in binary form.				   */			  case PW_TYPE_IFID:			  case PW_TYPE_IPV6ADDR:			  case PW_TYPE_IPV6PREFIX:			  case PW_TYPE_ABINARY:			  case PW_TYPE_STRING:			  case PW_TYPE_OCTETS:				  /*				   *  Encrypt the various password styles				   */				  switch (reply->flags.encrypt) {				  default:					  break;				  case FLAG_ENCRYPT_USER_PASSWORD:				    rad_pwencode((char *)reply->strvalue,						 &(reply->length),						 (const char *)secret,						 (const char *)packet->vector);				    break;				  case FLAG_ENCRYPT_TUNNEL_PASSWORD:					  if (!original) {						  librad_log("ERROR: No request packet, cannot encrypt Tunnel-Password attribute in the reply.");						  return -1;					  }					  rad_tunnel_pwencode(reply->strvalue,							      &(reply->length),							      secret,							      original->vector);					  break;				  case FLAG_ENCRYPT_ASCEND_SECRET:					  make_secret(digest, packet->vector,						      secret, reply->strvalue);					  memcpy(reply->strvalue, digest, AUTH_VECTOR_LEN );					  reply->length = AUTH_VECTOR_LEN;					  break;				  } /* switch over encryption flags */				  len = reply->length;				  /*				   *    Set the TAG at the beginning				   *    of the string if tagged.  If				   *    tag value is not valid for				   *    tagged attribute, make it 0x00				   *    per RFC 2868.  -cparker				   */				  if (reply->flags.has_tag) {					  if (TAG_VALID(reply->flags.tag)) {						  len++;						  *ptr++ = reply->flags.tag;					  } else if (reply->flags.encrypt == FLAG_ENCRYPT_TUNNEL_PASSWORD) {						  /*						   *  Tunnel passwords						   *  REQUIRE a tag,						   *  even if we don't						   *  have a valid						   *  tag.						   */						  len++;						  *ptr++ = 0x00;					  } /* else don't write a tag */				  } /* else the attribute doesn't have a tag */				  /*				   *	Ensure we don't go too far.				   *	The 'length' of the attribute				   *	may be 0..255, minus whatever				   *	octets are used in the attribute				   *	header.				   */				  allowed = 255;				  if (vsa_length_ptr) {					  allowed -= *vsa_length_ptr;				  } else {					  allowed -= *length_ptr;				  }				  if (len > allowed) {					  len = allowed;				  }				  *length_ptr += len;				  if (vsa_length_ptr) *vsa_length_ptr += len;				  /*				   *  If we have tagged attributes we can't assume that				   *  len == reply->length.  Use reply->length for copying				   *  the string data into the packet.  Use len for the				   *  true length of the string+tags.				   */				  memcpy(ptr, reply->strvalue, reply->length);				  ptr += reply->length;				  total_length += len;				  break;			  case PW_TYPE_INTEGER:			  case PW_TYPE_IPADDR:				  *length_ptr += 4;				  if (vsa_length_ptr) *vsa_length_ptr += 4;				  if (reply->type == PW_TYPE_INTEGER ) {				          /*  If tagged, the tag becomes the MSB of the value */				          if(reply->flags.has_tag) {					         /*  Tag must be ( 0x01 -> 0x1F ) OR 0x00  */					         if(!TAG_VALID(reply->flags.tag)) {						       reply->flags.tag = 0x00;						 }					         lvalue = htonl((reply->lvalue & 0xffffff) |								((reply->flags.tag & 0xff) << 24));					  } else {					         lvalue = htonl(reply->lvalue);					  }				  } else {					  /*					   *  IP address is already in					   *  network byte order.					   */					  lvalue = reply->lvalue;				  }				  memcpy(ptr, &lvalue, 4);				  ptr += 4;				  total_length += 4;				  break;				  /*				   *  There are no tagged date attributes.				   */			  case PW_TYPE_DATE:				  *length_ptr += 4;				  if (vsa_length_ptr) *vsa_length_ptr += 4;				  lvalue = htonl(reply->lvalue);				  memcpy(ptr, &lvalue, 4);				  ptr += 4;				  total_length += 4;				  break;			  default:				  break;			  }		  } /* done looping over all attributes */		  /*		   *	Fill in the rest of the fields, and copy		   *	the data over from the local stack to		   *	the newly allocated memory.		   *		   *	Yes, all this 'memcpy' is slow, but it means		   *	that we only allocate the minimum amount of		   *	memory for a request.		   */		  packet->data_len = total_length;		  packet->data = (uint8_t *) malloc(packet->data_len);

⌨️ 快捷键说明

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