www.pudn.com > RadiusSrv.rar > auth.cpp, change:2003-10-30,size:13440b


#include "Radiusd.h" 
#include "Radius.h" 
#include "../common/GKCommon.h" 
#include "../common/log.h" 
#include "../database/IPPhoneDB.h" 
#include "../function/xfunction.h" 
#include "../common/Des.h" 
 
extern IPPhoneDB IPPhoneDBLink; 
extern	string internationalPrefix;  //国际前缀 
extern	string internalPrefix;       //国内前缀 
 
const static char key[]={0,2,0,0,9,3,5,1,9,8,0,0,9,1,7}; 
/* 
 *	Check if account has expired, and if user may login now. 
 */ 
static int check_expiration(REQUEST *request) 
{ 
	int result; 
	VALUE_PAIR *check_item = request->config_items; 
 
	result = 0; 
	while (result == 0 && check_item != NULL) { 
 
		/* 
		 *	Check expiration date if we are doing password aging. 
		 */ 
		if (check_item->attribute == PW_EXPIRATION) { 
			/* 
			 *	Has this user's password expired? 
			 * 
			 *	If so, remove ALL reply attributes, 
			 *	and add our own Reply-Message, saying 
			 *	why they're being rejected. 
			 */ 
			if (check_item->lvalue < (unsigned) time(NULL)) { 
				VALUE_PAIR *vp; 
 
				result = -1; 
				vp = pairmake("Reply-Message", 
						"Password Has Expired\r\n", 
						T_OP_ADD); 
				pairfree(&request->reply->vps); 
				request->reply->vps = vp; 
				break; 
			} 
		} 
		check_item = check_item->next; 
	} 
	return result; 
} 
 
static void hex2bin(char *out, const char *in) 
{ 
	unsigned int tmp; 
 
	while (*in) { 
		sscanf(in, "%02x", &tmp); 
		*out = tmp; 
		out++; 
		in += 2; 
	} 
} 
/* 
 *	Process and reply to an authentication request 
 * 
 *	The return value of this function isn't actually used right now, so 
 *	it's not entirely clear if it is returning the right things. --Pac. 
 */ 
int rad_authenticate(REQUEST *request) 
{ 
	VALUE_PAIR	*namepair; 
	VALUE_PAIR	*check_item; 
//	VALUE_PAIR	*reply_item; 
	VALUE_PAIR	*auth_item; 
	VALUE_PAIR	*module_msg; 
	VALUE_PAIR	*tmp = NULL; 
	VALUE_PAIR	*autz_type_item = NULL; 
	VALUE_PAIR	*postauth_type_item = NULL; 
	int		result=0;//, r; 
//	char		umsg[MAX_STRING_LEN + 1]; 
	const char	*user_msg = NULL; 
	const char	*password; 
//	char		*exec_program; 
//	int		exec_wait; 
	int		seen_callback_id=0; 
////	char		buf[1024], logstr[1024]; 
	char		autz_retry = 0; 
	int		autz_type = 0; 
	int		postauth_type = 0; 
 
	password = ""; 
 
	/* 
	 *	Get the username from the request. 
	 * 
	 *	Note that namepair MAY be NULL, in which case there 
	 *	is no User-Name attribute in the request. 
	 */ 
	namepair = request->username; 
 
	/* 
	 *	Look for, and cache, passwords. 
	 */ 
	if (!request->password) { 
		request->password = pairfind(request->packet->vps, 
					     PW_PASSWORD); 
	} 
	   
	/* 
	 *	Discover which password we want to use. 
	 */ 
	auth_item = request->password; 
	if (auth_item) { 
		password = (const char *)auth_item->strvalue; 
 
	} else { 
		/* 
		 *	Maybe there's a CHAP-Password? 
		 */ 
		if ((auth_item = pairfind(request->packet->vps,  
				PW_CHAP_PASSWORD)) != NULL) { 
			password = "<CHAP-PASSWORD>"; 
		} else { 
			/* 
			 *	No password we recognize. 
			 */ 
			password = "<NO-PASSWORD>"; 
		} 
	} 
	request->password = auth_item; 
	 
	/* 
	 *	Get the user's authorization information from the database 
	 */ 
autz_redo: 
	if (!autz_retry){ 
		autz_type_item = pairfind(request->config_items, PW_AUTZ_TYPE); 
		if (autz_type_item){ 
			autz_type = autz_type_item->lvalue; 
			autz_retry = 1; 
			goto autz_redo; 
		} 
	} 
 
 
	/* 
	 *	If we haven't already proxied the packet, then check 
	 *	to see if we should.  Maybe one of the authorize 
	 *	modules has decided that a proxy should be used. If 
	 *	so, get out of here and send the packet. 
	 */ 
	if ((request->proxy == NULL) && 
			(pairfind(request->config_items, PW_PROXY_TO_REALM) != NULL)) { 
		return RLM_MODULE_OK; 
	} 
 
	/* 
	 *	Perhaps there is a Stripped-User-Name now. 
	 */ 
	namepair = request->username; 
 
	/* 
	 *	Validate the user 
	 */ 
	do { 
		if ((result = check_expiration(request)) < 0) 
				break; 
 
	//beging xinbao 
	VALUE_PAIR *ARQ_pair; 
	VALUE_PAIR password_pair; 
	VALUE_PAIR *terminal_info;//589825 
	VALUE_PAIR *response_pair; 
 
	char string[MAX_STRING_LEN]; 
	char *pszStr=string; 
	_EP_INFO EPInfo; 
 
	//确定是不是ARQ 
	ARQ_pair=pairfind(request->packet->vps, PW_CALLED_STATION_ID); 
 
	EPInfo.h323_ID=request->username->strvalue; 
 
	//不是h235登陆 
	if(password != "<CHAP-PASSWORD>") 
	{ 
		//是将密码段来保存用户的网络号码的 
		EPInfo.dialedDigits=request->password->strvalue;		 
	} 
	else 
	{ 
		//不是拨打电话的 
		if(ARQ_pair == NULL) 
		{ 
			//get E164 
			terminal_info=pairfind(request->packet->vps, 589825); 
			if(terminal_info) 
			{ 
				GetSubString(terminal_info->strvalue,string, ',', ';'); 
				EPInfo.dialedDigits=string; 
			} 
		} 
		else 
		{ 
			terminal_info=pairfind(request->packet->vps, 31); 
			if(terminal_info) 
			{ 
				EPInfo.dialedDigits=terminal_info->strvalue; 
			} 
		} 
	} 
 
	//提取号码前缀和用户号码 
	EPInfo.groupID=atoi((EPInfo.dialedDigits.substr(0,3)).c_str());; 
	EPInfo.dialedDigits.erase(0,3); 
 
	if(ARQ_pair==NULL) 
	{ 
		//h235 
		if(password == "<CHAP-PASSWORD>") 
		{ 
			LOG(5) ("validateUser by password:H323ID:%s, E164:%s, GroupID:%d", 
				EPInfo.h323_ID.c_str(), EPInfo.dialedDigits.c_str(), EPInfo.groupID); 
			//get passwd 
			if(IPPhoneDBLink.GetPhonePasswd(EPInfo, pszStr)) 
			{ 
				//decode password 
//				hex2bin(pszStr, pszStr); 
//				Des_Go(pszStr, pszStr, MAX_DES_CRYPT_LENGTH, key, sizeof(key), DECRYPT); 
 
//				password_pair.length=pszStr[0]; 
				password_pair.length=strlen(pszStr); 
				if(password_pair.length>0) 
				{ 
					//encode password us md5 
//					strncpy(password_pair.strvalue, ++pszStr, password_pair.length); 
					strcpy(password_pair.strvalue, pszStr);//, password_pair.length); 
					 
					rad_chap_encode(request->packet, string, 
						auth_item->strvalue[0], &password_pair); 
					 
					//compare 
					result=memcmp(string + 1, auth_item->strvalue + 1,	CHAP_VALUE_LENGTH)==0?0:1; 
				} 
				else 
					result=1; 
			} 
			else  
				result=1; 
		} 
		//H323-ID和E164验证		 
		else 
		{ 
			//attaction here 
			result=!IPPhoneDBLink.validateUser(EPInfo); 
			LOG(5) ("validateUser:H323ID:%s,E164:%s,GroupID:%d",  
				EPInfo.h323_ID.c_str(), EPInfo.dialedDigits.c_str(), EPInfo.groupID); 
		} 
	} 
	else  
	{ 
		//is it a ARQ 
		uint32 durationLimit=0; 
		_ARQ ARQ; 
 
		char szTmp[100]; 
		RewriteE164(ARQ_pair->strvalue, szTmp); 
 
		//IS it pc2pc 
		if(szTmp[0]=='0') 
		{ 
			ARQ.EPInfo=EPInfo; 
			ARQ.dialedDigits=szTmp; 
			durationLimit=IPPhoneDBLink.getDurationLimit(ARQ); 
			 
			DICT_ATTR		*attr; 
			char msg[MAX_STRING_LEN+19]; 
 
			_snprintf(msg, sizeof(msg), "h323-credit-time=%d", durationLimit); 
  
			//add pair 
			if ((response_pair = (value_pair *)malloc(sizeof(VALUE_PAIR))) == NULL)  
			{ 
				printf("out of memory"); 
				errno = ENOMEM; 
				return -1; 
			} 
		 
			memset(response_pair, 0, sizeof(VALUE_PAIR)); 
			if ((attr = dict_attrbyvalue(PW_VENDOR_SPECIFIC)) == NULL) 
			{ 
				_snprintf(response_pair->name, sizeof(response_pair->name), "Attr-%d", PW_VENDOR_SPECIFIC); 
				response_pair->type = PW_TYPE_OCTETS; 
			} 
			else 
			{ 
				strcpy(response_pair->name, attr->name); 
				response_pair->type = attr->type; 
				response_pair->flags = attr->flags; 
			} 
			//for cisco durationlimit 
			response_pair->attribute = (9<<16)+102; 
			response_pair->length = strlen(msg); 
			response_pair->oper = T_OP_EQ; 
			response_pair->next = NULL;	 
			strNcpy(response_pair->strvalue, msg, strlen(msg)+1); 
 
			pairadd(&request->reply->vps, response_pair); 
 
			LOG(5) ("H323ID:%s,E164:%s,GroupID:%d,called:%s,duration limit:%d",  
				ARQ.EPInfo.h323_ID.c_str(), ARQ.EPInfo.dialedDigits.c_str(),  
				EPInfo.groupID, ARQ.dialedDigits.c_str(), durationLimit); 
		} 
	} 
 
	//end xinbao 
		if (result > 0) { 
			/* don't reply! */ 
			return RLM_MODULE_HANDLED; 
		} 
	} while(0); 
	 
	/* 
	 *	Failed to validate the user. 
	 * 
	 *	We PRESUME that the code which failed will clean up 
	 *	request->reply->vps, to be ONLY the reply items it 
	 *	wants to send back. 
	 */ 
/*	if (result < 0) { 
		//("auth: Failed to validate the user."); 
		request->reply->code = PW_AUTHENTICATION_REJECT; 
 
		if ((module_msg = pairfind(request->packet->vps,PW_MODULE_FAILURE_MESSAGE)) != NULL){ 
			char msg[MAX_STRING_LEN+19]; 
 
			snprintf(msg, sizeof(msg), "Login incorrect (%s)", 
				 module_msg->strvalue); 
			rad_authlog(msg, request, 0); 
		} else { 
			rad_authlog("Login incorrect", request, 0); 
		} 
 
		/* double check: maybe the secret is wrong? */ 
	/*	if ((debug_flag > 1) && (auth_item != NULL) && 
				(auth_item->attribute == PW_PASSWORD)) { 
			u_char *p; 
 
			p = auth_item->strvalue; 
			while (*p != '\0') { 
				if (!isprint((int) *p)) { 
					//("  WARNING: Unprintable characters in the password.\n\t  Double-check the shared secret on the server and the NAS!"); 
					break; 
				} 
				p++; 
			} 
		} 
	} 
*/ 
	if (result >= 0 && 
			(check_item = pairfind(request->config_items, PW_SIMULTANEOUS_USE)) != NULL)  
	{ 
		VALUE_PAIR	*session_type; 
		int		sess_type = 0; 
 
		session_type = pairfind(request->config_items, PW_SESSION_TYPE); 
		if (session_type) 
			sess_type = session_type->lvalue; 
	} 
 
		/* 
		 *	User authenticated O.K. Now we have to check 
		 *	for the Simultaneous-Use parameter. 
		 */ 
/*		if (namepair && 
		    (r = module_checksimul(sess_type,request, check_item->lvalue)) != 0) { 
			char mpp_ok = 0; 
 
			if (r == 2){ 
				/* Multilink attempt. Check if port-limit > simultaneous-use */ 
/*				VALUE_PAIR *port_limit; 
 
				if ((port_limit = pairfind(request->reply->vps, PW_PORT_LIMIT)) != NULL && 
					port_limit->lvalue > check_item->lvalue){ 
					//("main auth: MPP is OK"); 
					mpp_ok = 1; 
				} 
			} 
			if (!mpp_ok){ 
				if (check_item->lvalue > 1) { 
		  		snprintf(umsg, sizeof(umsg),  
							"\r\nYou are already logged in %d times  - access denied\r\n\n", 
							(int)check_item->lvalue); 
					user_msg = umsg; 
				} else { 
					user_msg = "\r\nYou are already logged in - access denied\r\n\n"; 
				} 
 
				request->reply->code = PW_AUTHENTICATION_REJECT; 
 
				/* 
				 *	They're trying to log in too many times. 
				 *	Remove ALL reply attributes. 
				 */ 
//				pairfree(&request->reply->vps); 
/*				tmp = pairmake("Reply-Message", user_msg, T_OP_SET); 
				request->reply->vps = tmp; 
 
				snprintf(logstr, sizeof(logstr), "Multiple logins (max %d) %s", 
					check_item->lvalue, 
					r == 2 ? "[MPP attempt]" : ""); 
				rad_authlog(logstr, request, 1); 
 
				result = -1; 
			} 
		} 
	} 
*/ 
 
	/* 
	 *	Delete "normal" A/V pairs when using callback. 
	 * 
	 *	FIXME: This is stupid. The portmaster should accept 
	 *	these settings instead of insisting on using a 
	 *	dialout location. 
	 * 
	 *	FIXME2: Move this into the above exec thingy? 
	 *	(if you knew how I use the exec_wait, you'd understand). 
	 */ 
	if (seen_callback_id) { 
		pairdelete(&request->reply->vps, PW_FRAMED_PROTOCOL); 
		pairdelete(&request->reply->vps, PW_FRAMED_IP_ADDRESS); 
		pairdelete(&request->reply->vps, PW_FRAMED_IP_NETMASK); 
		pairdelete(&request->reply->vps, PW_FRAMED_ROUTE); 
		pairdelete(&request->reply->vps, PW_FRAMED_MTU); 
		pairdelete(&request->reply->vps, PW_FRAMED_COMPRESSION); 
		pairdelete(&request->reply->vps, PW_FILTER_ID); 
		pairdelete(&request->reply->vps, PW_PORT_LIMIT); 
		pairdelete(&request->reply->vps, PW_CALLBACK_NUMBER); 
	} 
 
	/* 
	 *	Filter (possibly multiple) Reply-Message attributes 
	 *	through radius_xlat, modifying them in place. 
	 */ 
/*	if (user_msg == NULL) { 
		reply_item = pairfind(request->reply->vps, PW_REPLY_MESSAGE); 
		while (reply_item) { 
			radius_xlat(buf, sizeof(reply_item->strvalue), 
				    (char *)reply_item->strvalue, request, NULL); 
			strNcpy((char *)reply_item->strvalue, buf, 
				sizeof(reply_item->strvalue)); 
			reply_item->length = strlen((char *)reply_item->strvalue); 
			user_msg = NULL; 
			reply_item = pairfind(reply_item->next, PW_REPLY_MESSAGE); 
		} 
	}*/ 
 
	/* 
	 *	Set the reply to Access-Accept, if it hasn't already 
	 *	been set to something.  (i.e. Access-Challenge) 
	 */ 
	if (request->reply->code == 0) 
	  request->reply->code = PW_AUTHENTICATION_ACK; 
 
	if ((module_msg = pairfind(request->packet->vps,PW_MODULE_SUCCESS_MESSAGE)) != NULL){ 
//		char msg[MAX_STRING_LEN+12]; 
 
	//	snprintf(msg, sizeof(msg), "Login OK (%s)", 
			// module_msg->strvalue); 
	///	rad_authlog(msg, request, 1); 
	} else { 
//		rad_authlog("Login OK", request, 1); 
		//printf("login ok\n"); 
	} 
 
 
	/* 
	 *	Do post-authentication calls. ignoring the return code. 
	 *	If the post-authentication 
	 */ 
/*	postauth_type_item = pairfind(request->config_items, PW_POST_AUTH_TYPE); 
	if (postauth_type_item) 
		postauth_type = postauth_type_item->lvalue; 
	result = module_post_auth(postauth_type, request); 
	switch (result) { 
	default: 
	  break; 
	   
	  /* 
	   *	The module failed, or said to reject the user: Do so. 
	   */ 
/*	case RLM_MODULE_FAIL: 
	case RLM_MODULE_REJECT: 
	case RLM_MODULE_USERLOCK: 
	case RLM_MODULE_INVALID: 
	  request->reply->code = PW_AUTHENTICATION_REJECT; 
	  result = RLM_MODULE_REJECT; 
	  break; 
 
	  /* 
	   *	The module had a number of OK return codes. 
	   */ 
/*	case RLM_MODULE_NOTFOUND: 
	case RLM_MODULE_NOOP: 
	case RLM_MODULE_UPDATED: 
	case RLM_MODULE_OK: 
	case RLM_MODULE_HANDLED: 
	  result = RLM_MODULE_OK; 
	  break; 
*/	 
 
	return result; 
}