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

📄 radius.c

📁 使用最广泛的radius的linux的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
			/*			 *	attrlen was checked above.			 */			memcpy(&lvalue, ptr, 4);			myvendor = ntohl(lvalue);			/*			 *	Zero isn't allowed.			 */			if (myvendor == 0) goto create_pair;			/*			 *	This is an implementation issue.			 *	We currently pack vendor into the upper			 *	16 bits of a 32-bit attribute number,			 *	so we can't handle vendor numbers larger			 *	than 16 bits.			 */			if (myvendor > 65535) goto create_pair;			vsa_tlen = vsa_llen = 1;			dv = dict_vendorbyvalue(myvendor);			if (dv) {				vsa_tlen = dv->type;				vsa_llen = dv->length;			}			/*			 *	Sweep through the list of VSA's,			 *	seeing if they exactly fill the			 *	outer Vendor-Specific attribute.			 *			 *	If not, create a raw Vendor-Specific.			 */			subptr = ptr + 4;			sublen = attrlen - 4;			/*			 *	See if we can parse it.			 */			do {				int myattr = 0;				/*				 *	Don't have a type, it's bad.				 */				if (sublen < vsa_tlen) goto create_pair;				/*				 *	Ensure that the attribute number				 *	is OK.				 */				switch (vsa_tlen) {				case 1:					myattr = subptr[0];					break;				case 2:					myattr = (subptr[0] << 8) | subptr[1];					break;				case 4:					if ((subptr[0] != 0) ||					    (subptr[1] != 0)) goto create_pair;					myattr = (subptr[2] << 8) | subptr[3];					break;					/*					 *	Our dictionary is broken.					 */				default:					goto create_pair;				}				/*				 *	Not enough room for one more				 *	attribute.  Die!				 */				if (sublen < vsa_tlen + vsa_llen) goto create_pair;				switch (vsa_llen) {				case 0:					attribute = (myvendor << 16) | myattr;					ptr += 4 + vsa_tlen;					attrlen -= (4 + vsa_tlen);					packet_length -= 4 + vsa_tlen;					goto create_pair;				case 1:					if (subptr[vsa_tlen] < (vsa_tlen + vsa_llen))						goto create_pair;					if (subptr[vsa_tlen] > sublen)						goto create_pair;					sublen -= subptr[vsa_tlen];					subptr += subptr[vsa_tlen];					break;				case 2:					if (subptr[vsa_tlen] != 0) goto create_pair;					if (subptr[vsa_tlen + 1] < (vsa_tlen + vsa_llen))						goto create_pair;					if (subptr[vsa_tlen + 1] > sublen)						goto create_pair;					sublen -= subptr[vsa_tlen + 1];					subptr += subptr[vsa_tlen + 1];					break;					/*					 *	Our dictionaries are					 *	broken.					 */				default:					goto create_pair;				}			} while (sublen > 0);			vendorcode = myvendor;			vendorlen = attrlen - 4;			packet_length -= 4;			ptr += 4;		}		/*		 *	attrlen is the length of this attribute.		 *	total_len is the length of the encompassing		 *	attribute.		 */		switch (vsa_tlen) {		case 1:			attribute = ptr[0];			break;		case 2:			attribute = (ptr[0] << 8) | ptr[1];			break;		default:	/* can't hit this. */			return -1;		}		attribute |= (vendorcode << 16);		ptr += vsa_tlen;		switch (vsa_llen) {		case 1:			attrlen = ptr[0] - (vsa_tlen + vsa_llen);			break;		case 2:			attrlen = ptr[1] - (vsa_tlen + vsa_llen);			break;		default:	/* can't hit this. */			return -1;		}		ptr += vsa_llen;		vendorlen -= vsa_tlen + vsa_llen + attrlen;		if (vendorlen == 0) vendorcode = 0;		packet_length -= (vsa_tlen + vsa_llen);		/*		 *	Create the attribute, setting the default type		 *	to 'octets'.  If the type in the dictionary		 *	is different, then the dictionary type will		 *	over-ride this one.		 *		 *	If the attribute has no data, then discard it.		 */	create_pair:		if (!attrlen) goto next;		pair = rad_attr2vp(packet, original, secret,				   attribute, attrlen, ptr);		if (!pair) {			pairfree(&packet->vps);			librad_log("out of memory");			return -1;		}		*tail = pair;		while (pair) {			num_attributes++;			debug_pair(pair);			tail = &pair->next;			pair = pair->next;		}		/*		 *	VSA's may not have been counted properly in		 *	rad_packet_ok() above, as it is hard to count		 *	then without using the dictionary.  We		 *	therefore enforce the limits here, too.		 */		if ((librad_max_attributes > 0) &&		    (num_attributes > librad_max_attributes)) {			char host_ipaddr[128];			pairfree(&packet->vps);			librad_log("WARNING: Possible DoS attack from host %s: Too many attributes in request (received %d, max %d are allowed).",				   inet_ntop(packet->src_ipaddr.af,					     &packet->src_ipaddr.ipaddr,					     host_ipaddr, sizeof(host_ipaddr)),				   num_attributes, librad_max_attributes);			return -1;		}		    next:		ptr += attrlen;		packet_length -= attrlen;	}	/*	 *	Merge information from the outside world into our	 *	random pool.	 */	fr_rand_seed(packet->data, AUTH_HDR_LEN);	return 0;}/* *	Encode password. * *	We assume that the passwd buffer passed is big enough. *	RFC2138 says the password is max 128 chars, so the size *	of the passwd buffer must be at least 129 characters. *	Preferably it's just MAX_STRING_LEN. * *	int *pwlen is updated to the new length of the encrypted *	password - a multiple of 16 bytes. */int rad_pwencode(char *passwd, size_t *pwlen, const char *secret,		 const uint8_t *vector){	FR_MD5_CTX context, old;	uint8_t	digest[AUTH_VECTOR_LEN];	int	i, n, secretlen;	int	len;	/*	 *	RFC maximum is 128 bytes.	 *	 *	If length is zero, pad it out with zeros.	 *	 *	If the length isn't aligned to 16 bytes,	 *	zero out the extra data.	 */	len = *pwlen;	if (len > 128) len = 128;	if (len == 0) {		memset(passwd, 0, AUTH_PASS_LEN);		len = AUTH_PASS_LEN;	} else if ((len % AUTH_PASS_LEN) != 0) {		memset(&passwd[len], 0, AUTH_PASS_LEN - (len % AUTH_PASS_LEN));		len += AUTH_PASS_LEN - (len % AUTH_PASS_LEN);	}	*pwlen = len;	/*	 *	Use the secret to setup the decryption digest	 */	secretlen = strlen(secret);	fr_MD5Init(&context);	fr_MD5Update(&context, (const uint8_t *) secret, secretlen);	old = context;		/* save intermediate work */	/*	 *	Encrypt it in place.  Don't bother checking	 *	len, as we've ensured above that it's OK.	 */	for (n = 0; n < len; n += AUTH_PASS_LEN) {		if (n == 0) {			fr_MD5Update(&context, vector, AUTH_PASS_LEN);			fr_MD5Final(digest, &context);		} else {			context = old;			fr_MD5Update(&context,				     (uint8_t *) passwd + n - AUTH_PASS_LEN,				     AUTH_PASS_LEN);			fr_MD5Final(digest, &context);		}		for (i = 0; i < AUTH_PASS_LEN; i++) {			passwd[i + n] ^= digest[i];		}	}	return 0;}/* *	Decode password. */int rad_pwdecode(char *passwd, size_t pwlen, const char *secret,		 const uint8_t *vector){	FR_MD5_CTX context, old;	uint8_t	digest[AUTH_VECTOR_LEN];	int	i;	size_t	n, secretlen;	/*	 *	The RFC's say that the maximum is 128.	 *	The buffer we're putting it into above is 254, so	 *	we don't need to do any length checking.	 */	if (pwlen > 128) pwlen = 128;	/*	 *	Catch idiots.	 */	if (pwlen == 0) goto done;	/*	 *	Use the secret to setup the decryption digest	 */	secretlen = strlen(secret);	fr_MD5Init(&context);	fr_MD5Update(&context, (const uint8_t *) secret, secretlen);	old = context;		/* save intermediate work */	/*	 *	The inverse of the code above.	 */	for (n = 0; n < pwlen; n += AUTH_PASS_LEN) {		if (n == 0) {			fr_MD5Update(&context, vector, AUTH_VECTOR_LEN);			fr_MD5Final(digest, &context);			context = old;			if (pwlen > AUTH_PASS_LEN) {				fr_MD5Update(&context, (uint8_t *) passwd,					     AUTH_PASS_LEN);			}		} else {			fr_MD5Final(digest, &context);			context = old;			if (pwlen > (n + AUTH_PASS_LEN)) {				fr_MD5Update(&context, (uint8_t *) passwd + n,					     AUTH_PASS_LEN);			}		}		for (i = 0; i < AUTH_PASS_LEN; i++) {			passwd[i + n] ^= digest[i];		}	} done:	passwd[pwlen] = '\0';	return strlen(passwd);}/* *	Encode Tunnel-Password attributes when sending them out on the wire. * *	int *pwlen is updated to the new length of the encrypted *	password - a multiple of 16 bytes. * *      This is per RFC-2868 which adds a two char SALT to the initial intermediate *      value MD5 hash. */int rad_tunnel_pwencode(char *passwd, size_t *pwlen, const char *secret,			const uint8_t *vector){	uint8_t	buffer[AUTH_VECTOR_LEN + MAX_STRING_LEN + 3];	unsigned char	digest[AUTH_VECTOR_LEN];	char*   salt;	int	i, n, secretlen;	unsigned len, n2;	len = *pwlen;	if (len > 127) len = 127;	/*	 * Shift the password 3 positions right to place a salt and original	 * length, tag will be added automatically on packet send	 */	for (n=len ; n>=0 ; n--) passwd[n+3] = passwd[n];	salt = passwd;	passwd += 2;	/*	 * save original password length as first password character;	 */	*passwd = len;	len += 1;	/*	 *	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..	 */	salt[0] = (0x80 | ( ((salt_offset++) & 0x0f) << 3) |		   (fr_rand() & 0x07));	salt[1] = fr_rand();	/*	 *	Padd password to multiple of AUTH_PASS_LEN bytes.	 */	n = len % AUTH_PASS_LEN;	if (n) {		n = AUTH_PASS_LEN - n;		for (; n > 0; n--, len++)			passwd[len] = 0;	}	/* set new password length */	*pwlen = len + 2;	/*	 *	Use the secret to setup the decryption digest	 */	secretlen = strlen(secret);	memcpy(buffer, secret, secretlen);	for (n2 = 0; n2 < len; n2+=AUTH_PASS_LEN) {		if (!n2) {			memcpy(buffer + secretlen, vector, AUTH_VECTOR_LEN);			memcpy(buffer + secretlen + AUTH_VECTOR_LEN, salt, 2);			fr_md5_calc(digest, buffer, secretlen + AUTH_VECTOR_LEN + 2);		} else {			memcpy(buffer + secretlen, passwd + n2 - AUTH_PASS_LEN, AUTH_PASS_LEN);			fr_md5_calc(digest, buffer, secretlen + AUTH_PASS_LEN);		}		for (i = 0; i < AUTH_PASS_LEN; i++) {			passwd[i + n2] ^= digest[i];		}	}	passwd[n2] = 0;	return 0;}/* *	Decode Tunnel-Password encrypted attributes. * *      Defined in RFC-2868, this uses a two char SALT along with the *      initial intermediate value, to differentiate it from the *      above. */int rad_tunnel_pwdecode(uint8_t *passwd, size_t *pwlen, const char *secret,			const uint8_t *vector){	FR_MD5_CTX  context, old;	uint8_t		digest[AUTH_VECTOR_LEN];	int		secretlen;	unsigned	i, n, len, reallen;	len = *pwlen;	/*	 *	We need at least a salt.	 */	if (len < 2) {		librad_log("tunnel password is too short");		return -1;	}	/*	 *	There's a salt, but no password.  Or, there's a salt	 *	and a 'data_len' octet.  It's wrong, but at least we	 *	can figure out what it means: the password is empty.	 *	 *	Note that this means we ignore the 'data_len' field,	 *	if the attribute length tells us that there's no	 *	more data.  So the 'data_len' field may be wrong,	 *	but that's ok...	 */	if (len <= 3) {		passwd[0] = 0;		*pwlen = 0;		return 0;	}	len -= 2;		/* discount the salt */	/*	 *	Use the secret to setup the decryption digest	 */	secretlen = strlen(secret);	fr_MD5Init(&context);	fr_MD5Update(&context, (const uint8_t *) secret, secretlen);	old = context;		/* save intermediate work */	/*	 *	Set up the initial key:	 *	 *	 b(1) = MD5(secret + vector + salt)	 */	fr_MD5Update(&context, vector, AUTH_VECTOR_LEN);	fr_MD5Update(&context, passwd, 2);	reallen = 0;	for (n = 0; n < len; n += AUTH_PASS_LEN) {		int base = 0;		if (n == 0) {			fr_MD5Final(digest, &context);			context = old;			/*			 *	A quick check: decrypt the first octet			 *	of the password, which is the			 *	'data_len' field.  Ensure it's sane.			 */			reallen = passwd[2] ^ digest[0];			if (reallen >= len) {				librad_log("tunnel password is too long for the attribute");				return -1;			}			fr_MD5Update(&context, passwd + 2, AUTH_PASS_LEN);			base = 1;		} else {			fr_MD5Final(digest, &context);			context = old;			fr_MD5Update(&context, passwd + n + 2, AUTH_PASS_LEN);		}		for (i = base; i < AUTH_PASS_LEN; i++) {			passwd[n + i - 1] = passwd[n + i + 2] ^ digest[i];		}	}	/*	 *	See make_tunnel_password, above.	 */	if (reallen > 239) reallen = 239;	*pwlen = reallen;	passwd[reallen] = 0;	return reallen;}/* *	Encode a CHAP password * *	FIXME: might not work with Ascend because *	we use vp->length, and Ascend gear likes

⌨️ 快捷键说明

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