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

📄 rlm_mschap.c

📁 RADIUS认证协议
💻 C
📖 第 1 页 / 共 3 页
字号:
/* * rlm_mschap.c * * Version:	$Id: rlm_mschap.c,v 1.59.2.2 2005/08/24 14:37:52 nbk 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 2000,2001  The FreeRADIUS server project *//* *  mschap.c    MS-CHAP module * *  This implements MS-CHAP, as described in RFC 2548 * *  http://www.freeradius.org/rfc/rfc2548.txt * *//* *  If you have any questions on NTLM (Samba) passwords *  support, LM authentication and MS-CHAP v2 support *  please contact * *  Vladimir Dubrovin	vlad@sandy.ru *  aka *  ZARAZA		3APA3A@security.nnov.ru *//*  MPPE support from Takahiro Wagatsuma <waga@sic.shibaura-it.ac.jp> */#include	"autoconf.h"#include	"libradius.h"#include	<stdio.h>#include	<stdlib.h>#include    	<string.h>#include 	<ctype.h>#include	"radiusd.h"#include	"modules.h"#include        "md4.h"#include        "md5.h"#include	"sha1.h"#include	"rad_assert.h"#include	"smbdes.h"static const char rcsid[] = "$Id: rlm_mschap.c,v 1.59.2.2 2005/08/24 14:37:52 nbk Exp $";static const char *letters = "0123456789ABCDEF";/* *	hex2bin converts hexadecimal strings into binary */static int hex2bin (const char *szHex, unsigned char* szBin, int len){	char * c1, * c2;	int i;   	for (i = 0; i < len; i++) {		if( !(c1 = memchr(letters, toupper((int) szHex[i << 1]), 16)) ||		    !(c2 = memchr(letters, toupper((int) szHex[(i << 1) + 1]), 16)))		     break;                 szBin[i] = ((c1-letters)<<4) + (c2-letters);        }        return i;}/* *	bin2hex creates hexadecimal presentation *	of binary data */static void bin2hex (const unsigned char *szBin, char *szHex, int len){	int i;	for (i = 0; i < len; i++) {		szHex[i<<1] = letters[szBin[i] >> 4];		szHex[(i<<1) + 1] = letters[szBin[i] & 0x0F];	}}/* Allowable account control bits */#define ACB_DISABLED   0x0001  /* 1 = User account disabled */#define ACB_HOMDIRREQ  0x0002  /* 1 = Home directory required */#define ACB_PWNOTREQ   0x0004  /* 1 = User password not required */#define ACB_TEMPDUP    0x0008  /* 1 = Temporary duplicate account */#define ACB_NORMAL     0x0010  /* 1 = Normal user account */#define ACB_MNS        0x0020  /* 1 = MNS logon user account */#define ACB_DOMTRUST   0x0040  /* 1 = Interdomain trust account */#define ACB_WSTRUST    0x0080  /* 1 = Workstation trust account */#define ACB_SVRTRUST   0x0100  /* 1 = Server trust account */#define ACB_PWNOEXP    0x0200  /* 1 = User password does not expire */#define ACB_AUTOLOCK   0x0400  /* 1 = Account auto locked */static int pdb_decode_acct_ctrl(const char *p){	int acct_ctrl = 0;	int finished = 0;	/*	 * Check if the account type bits have been encoded after the	 * NT password (in the form [NDHTUWSLXI]).	 */	if (*p != '[') return 0;	for (p++; *p && !finished; p++) {		switch (*p) {			case 'N': /* 'N'o password. */			  acct_ctrl |= ACB_PWNOTREQ;			  break;			case 'D':  /* 'D'isabled. */			  acct_ctrl |= ACB_DISABLED ;			  break;			case 'H':  /* 'H'omedir required. */			  acct_ctrl |= ACB_HOMDIRREQ;			  break;			case 'T': /* 'T'emp account. */			  acct_ctrl |= ACB_TEMPDUP;			  break;			case 'U': /* 'U'ser account (normal). */			  acct_ctrl |= ACB_NORMAL;			  break;			case 'M': /* 'M'NS logon user account. What is this? */			  acct_ctrl |= ACB_MNS;			  break;			case 'W': /* 'W'orkstation account. */			  acct_ctrl |= ACB_WSTRUST;			  break;			case 'S': /* 'S'erver account. */			  acct_ctrl |= ACB_SVRTRUST;			  break;			case 'L': /* 'L'ocked account. */			  acct_ctrl |= ACB_AUTOLOCK;			  break;			case 'X': /* No 'X'piry on password */			  acct_ctrl |= ACB_PWNOEXP;			  break;			case 'I': /* 'I'nterdomain trust account. */			  acct_ctrl |= ACB_DOMTRUST;			  break;		        case ' ': /* ignore spaces */			  break;			case ':':			case '\n':			case '\0':			case ']':			default:			  finished = 1;			  break;		}	}	return acct_ctrl;}/* *	ntpwdhash converts Unicode password to 16-byte NT hash *	with MD4 */static void ntpwdhash (unsigned char *szHash, const char *szPassword){	char szUnicodePass[513];	int nPasswordLen;	int i;	/*	 *	NT passwords are unicode.  Convert plain text password	 *	to unicode by inserting a zero every other byte	 */	nPasswordLen = strlen(szPassword);	for (i = 0; i < nPasswordLen; i++) {		szUnicodePass[i << 1] = szPassword[i];		szUnicodePass[(i << 1) + 1] = 0;	}	/* Encrypt Unicode password to a 16-byte MD4 hash */	md4_calc(szHash, szUnicodePass, (nPasswordLen<<1) );}/* *	challenge_hash() is used by mschap2() and auth_response() *	implements RFC2759 ChallengeHash() *	generates 64 bit challenge */static void challenge_hash( const char *peer_challenge,			    const char *auth_challenge,			    const char *user_name, char *challenge ){	SHA1_CTX Context;	unsigned char hash[20];	SHA1Init(&Context);	SHA1Update(&Context, peer_challenge, 16);	SHA1Update(&Context, auth_challenge, 16);	SHA1Update(&Context, user_name, strlen(user_name));	SHA1Final(hash, &Context);	memcpy(challenge, hash, 8);}/* *	auth_response() generates MS-CHAP v2 SUCCESS response *	according to RFC 2759 GenerateAuthenticatorResponse() *	returns 42-octet response string */static void auth_response(const char *username,			  const unsigned char *nt_hash_hash,			  unsigned char *ntresponse,			  char *peer_challenge, char *auth_challenge,			  char *response){	SHA1_CTX Context;	const unsigned char magic1[39] =	{0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,	 0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,	 0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,	 0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74};	const unsigned char magic2[41] =	{0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,	 0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,	 0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,	 0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,	 0x6E};        char challenge[8];	unsigned char digest[20];	SHA1Init(&Context);	SHA1Update(&Context, nt_hash_hash, 16);	SHA1Update(&Context, ntresponse, 24);	SHA1Update(&Context, magic1, 39);	SHA1Final(digest, &Context);	challenge_hash(peer_challenge, auth_challenge, username, challenge);	SHA1Init(&Context);	SHA1Update(&Context, digest, 20);	SHA1Update(&Context, challenge, 8);	SHA1Update(&Context, magic2, 41);	SHA1Final(digest, &Context);	/*	 *	Encode the value of 'Digest' as "S=" followed by	 *	40 ASCII hexadecimal digits and return it in	 *	AuthenticatorResponse.	 *	For example,	 *	"S=0123456789ABCDEF0123456789ABCDEF01234567"	 */ 	response[0] = 'S';	response[1] = '=';	bin2hex(digest, response + 2, 20);}typedef struct rlm_mschap_t {	int use_mppe;	int require_encryption;        int require_strong;        int with_ntdomain_hack;	/* this should be in another module */	char *passwd_file;	char *xlat_name;	char *auth_type;	/* I don't think this is needed... */	char *ntlm_auth;} rlm_mschap_t;/* *	Does dynamic translation of strings. * *	Pulls NT-Response, LM-Response, or Challenge from MSCHAP *	attributes. */static int mschap_xlat(void *instance, REQUEST *request,		       char *fmt, char *out, size_t outlen,		       RADIUS_ESCAPE_STRING func){	int		i, data_len;	uint8_t		*data = NULL;	uint8_t		buffer[8];	VALUE_PAIR	*user_name;	VALUE_PAIR	*chap_challenge, *response;	rlm_mschap_t	*inst = instance;	chap_challenge = response = NULL;	func = func;		/* -Wunused */	/*	 *	Challenge means MS-CHAPv1 challenge, or	 *	hash of MS-CHAPv2 challenge, and peer challenge.	 */	if (strcasecmp(fmt, "Challenge") == 0) {		chap_challenge = pairfind(request->packet->vps,					  PW_MSCHAP_CHALLENGE);		if (!chap_challenge) {			DEBUG2("  rlm_mschap: No MS-CHAP-Challenge in the request.");			return 0;		}		/*		 *	MS-CHAP-Challenges are 8 octets,		 *	for MS-CHAPv2		 */		if (chap_challenge->length == 8) {			DEBUG2(" mschap1: %02x", chap_challenge->strvalue[0]);			data = chap_challenge->strvalue;			data_len = 8;			/*			 *	MS-CHAP-Challenges are 16 octets,			 *	for MS-CHAPv2.			 */		} else if (chap_challenge->length == 16) {			char *username_string;			DEBUG2(" mschap2: %02x", chap_challenge->strvalue[0]);			response = pairfind(request->packet->vps,					    PW_MSCHAP2_RESPONSE);			if (!response) {				DEBUG2("  rlm_mschap: MS-CHAP2-Response is required to calculate MS-CHAPv1 challenge.");				return 0;			}			/*			 *	Responses are 50 octets.			 */			if (response->length < 50) {				radlog(L_AUTH, "rlm_mschap: MS-CHAP-Response has the wrong format.");				return 0;			}			user_name = pairfind(request->packet->vps,					     PW_USER_NAME);			if (!user_name) {				DEBUG2("  rlm_mschap: User-Name is required to calculateMS-CHAPv1 Challenge.");				return 0;			}			/*			 *	with_ntdomain_hack moved here, too.			 */			if ((username_string = strchr(user_name->strvalue, '\\')) != NULL) {				if (inst->with_ntdomain_hack) {					username_string++;				} else {					DEBUG2("  rlm_mschap: NT Domain delimeter found, should we have enabled with_ntdomain_hack?");					username_string = user_name->strvalue;				}			} else {				username_string = user_name->strvalue;			}			/*			 *	Get the MS-CHAPv1 challenge			 *	from the MS-CHAPv2 peer challenge,			 *	our challenge, and the user name.			 */			challenge_hash(response->strvalue + 2,				       chap_challenge->strvalue,				       username_string, buffer);			data = buffer;			data_len = 8;		} else {			DEBUG2("  rlm_mschap: Invalid MS-CHAP challenge length");			return 0;		}				/*		 *	Get the MS-CHAPv1 response, or the MS-CHAPv2		 *	response.		 */	} else if (strcasecmp(fmt, "NT-Response") == 0) {		response = pairfind(request->packet->vps,				    PW_MSCHAP_RESPONSE);		if (!response) response = pairfind(request->packet->vps,						   PW_MSCHAP2_RESPONSE);		if (!response) {			DEBUG2("  rlm_mschap: No MS-CHAP-Response or MS-CHAP2-Response was found in the request.");			return 0;		}		/*		 *	For MS-CHAPv1, the NT-Response exists only		 *	if the second octet says so.		 */		if ((response->attribute == PW_MSCHAP_RESPONSE) &&		    ((response->strvalue[1] & 0x01) == 0)) {			DEBUG2("  rlm_mschap: No NT-Response in MS-CHAP-Response");			return 0;		}		/*		 *	MS-CHAP-Response and MS-CHAP2-Response have		 *	the NT-Response at the same offset, and are		 *	the same length.		 */		data = response->strvalue + 26;		data_len = 24;				/*		 *	LM-Response is deprecated, and exists only		 *	in MS-CHAPv1, and not often there.		 */	} else if (strcasecmp(fmt, "LM-Response") == 0) {		response = pairfind(request->packet->vps,				    PW_MSCHAP_RESPONSE);		if (!response) {			DEBUG2("  rlm_mschap: No MS-CHAP-Response was found in the request.");			return 0;		}		/*		 *	For MS-CHAPv1, the NT-Response exists only		 *	if the second octet says so.		 */		if ((response->strvalue[1] & 0x01) != 0) {			DEBUG2("  rlm_mschap: No LM-Response in MS-CHAP-Response");

⌨️ 快捷键说明

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