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

📄 radius.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
		}	}	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){	FR_MD5_CTX context, old;	uint8_t	digest[AUTH_VECTOR_LEN];	uint8_t passwd[MAX_STRING_LEN + AUTH_VECTOR_LEN];	int	i, n;	int	len;	/*	 *	Be paranoid.	 */	if (room > 253) room = 253;	/*	 *	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) |		     (fr_rand() & 0x07));	passwd[1] = fr_rand();	passwd[2] = inlen;	/* length of the password string */	fr_MD5Init(&context);	fr_MD5Update(&context, (const uint8_t *) secret, strlen(secret));	old = context;	fr_MD5Update(&context, vector, AUTH_VECTOR_LEN);	fr_MD5Update(&context, &passwd[0], 2);	for (n = 0; n < len; n += AUTH_PASS_LEN) {		if (n > 0) {			context = old;			fr_MD5Update(&context,				       passwd + 2 + n - AUTH_PASS_LEN,				       AUTH_PASS_LEN);		}		fr_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) {		*(ptr++) = vp->attribute & 0xFF;		length_ptr = ptr;		*(ptr++) = 2;		total_length += 2;	} else {		int vsa_tlen = 1;		int vsa_llen = 1;		DICT_VENDOR *dv = dict_vendorbyvalue(vendorcode);		/*		 *	This must be an RFC-format attribute.  If it		 *	wasn't, then the "decode" function would have		 *	made a Vendor-Specific attribute (i.e. type		 *	26), and we would have "vendorcode == 0" here.		 */		if (dv) {			vsa_tlen = dv->type;			vsa_llen = dv->length;		}		/*		 *	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;		switch (vsa_tlen) {		case 1:			ptr[0] = (vp->attribute & 0xFF);			break;		case 2:			ptr[0] = ((vp->attribute >> 8) & 0xFF);			ptr[1] = (vp->attribute & 0xFF);			break;		case 4:			ptr[0] = 0;			ptr[1] = 0;			ptr[2] = ((vp->attribute >> 8) & 0xFF);			ptr[3] = (vp->attribute & 0xFF);			break;		default:			return 0; /* silently discard it */		}		ptr += vsa_tlen;		switch (vsa_llen) {		case 0:			length_ptr = vsa_length_ptr;			vsa_length_ptr = NULL;			break;		case 1:			ptr[0] = 0;			length_ptr = ptr;			break;		case 2:			ptr[0] = 0;			ptr[1] = 0;			length_ptr = ptr + 1;			break;		default:			return 0; /* silently discard it */		}		ptr += vsa_llen;		total_length += vsa_tlen + vsa_llen;		if (vsa_length_ptr) *vsa_length_ptr += vsa_tlen + vsa_llen;		*length_ptr += vsa_tlen + vsa_llen;	}	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->vp_octets;	len = vp->length;	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_BYTE:		len = 1;	/* just in case */		array[0] = vp->vp_integer & 0xff;		data = array;		offset = 0;		break;	case PW_TYPE_SHORT:		len = 2;	/* just in case */		array[0] = (vp->vp_integer >> 8) & 0xff;		array[1] = vp->vp_integer & 0xff;		data = array;		offset = 0;		break;	case PW_TYPE_INTEGER:		len = 4;	/* just in case */		lvalue = htonl(vp->vp_integer);		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->vp_ipaddr;		len = 4;	/* just in case */		break;		/*		 *  There are no tagged date attributes.		 */	case PW_TYPE_DATE:		lvalue = htonl(vp->vp_date);		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:		/*		 *	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;        	switch (packet->code) {	        case PW_AUTHENTICATION_ACK:        	case PW_AUTHENTICATION_REJECT:        	case PW_ACCESS_CHALLENGE:        	default:			if (!original) {				librad_log("ERROR: No request packet, cannot encrypt %s attribute in the vp.", vp->name);				return -1;			}			make_tunnel_passwd(ptr + offset, &len,					   data, len, 255 - offset - total_length,					   secret, original->vector);                	break;	        case PW_ACCOUNTING_REQUEST:        	case PW_DISCONNECT_REQUEST:	        case PW_COA_REQUEST:			make_tunnel_passwd(ptr + offset, &len,					   data, len, 255 - offset - total_length,					   secret, packet->vector);	                break;        	}		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;	const char	*what;	char		ip_buffer[128];	/*	 *	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];	if ((packet->code > 0) && (packet->code < MAX_PACKET_CODE)) {		what = packet_codes[packet->code];	} else {		what = "Reply";	}	DEBUG("Sending %s of id %d to %s port %d\n",	      what, packet->id,	      inet_ntop(packet->dst_ipaddr.af,			&packet->dst_ipaddr.ipaddr,			ip_buffer, sizeof(ip_buffer)),	      packet->dst_port);	/*	 *	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;	hdr->id = packet->id;	memcpy(hdr->vector, packet->vector, sizeof(hdr->vector));	total_length = AUTH_HDR_LEN;	/*	 *	Load up the configuration values for the user	 */	ptr = hdr->data;	packet->offset = 0;	/*	 *	FIXME: Loop twice over the reply list.  The first time,	 *	calculate the total length of data.  The second time,	 *	allocate the memory, and fill in the VP's.	 *	 *	Hmm... this may be slower than just doing a small	 *	memcpy.	 */	/*	 *	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)) {#ifndef NDEBUG			/*			 *	Permit the admin to send BADLY formatted			 *	attributes with a debug build.			 */			if (reply->attribute == PW_RAW_ATTRIBUTE) {				memcpy(ptr, reply->vp_octets, reply->length);				len = reply->length;				goto next;			}#endif			continue;		}		/*		 *	Set the Message-Authenticator to the correct		 *	length and initial value.		 */		if (reply->attribute == PW_MESSAGE_AUTHENTICATOR) {			reply->length = AUTH_VECTOR_LEN;			memset(reply->vp_strvalue, 0, AUTH_VECTOR_LEN);			/*			 *	Cache the offset to the			 *	Message-Authenticator			 */			packet->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);		len = rad_vp2attr(packet, original, secret, reply, ptr);		if (len < 0) return -1;		/*		 *	Check that the packet is no more than 4k in		 *	size, AFTER writing the attribute past the 4k		 *	boundary, but BEFORE deciding to increase the		 *	size of the packet. Note that the 'data'		 *	buffer, above, is one attribute longer than		 *	necessary, in order to permit this overflow.		 */		if ((total_length + len) > MAX_PACKET_LEN) {			break;		}	next:		ptr += len;		total_length += len;	} /* 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);	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(total_length));	return 0;}/* *	Sign a previously encoded packet. */int rad_sign(RADIUS_PACKET *packet, const RADIUS_PACKET *original,

⌨️ 快捷键说明

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