<?php
/******************************************************************
*	interfaces to operate OTP authentication system
*/
include_once("config/otp_config.php");
include_once("encrypt/secu_otp_hmacfnv.php");
include_once("otp_const.php");
include_once("dbinterface/".$dbconfig['db_prefix']."otp_myclass.php");
include_once("encrypt/otp_AES.php");

/******************************************************************
* function: _date_convert
*	remark:		convert the time into a correct format
******************************************************************/
function _date_convert($intime)
{
	global $dbconfig;
	if(4 == $dbconfig['db_dbtype'])
	{
		return "to_date('$intime')";
	}
	else
	{
		return "'$intime'";
	}
}
/******************************************************************
* function: secuotp_auth
* params	:	$sUsername
*						$sPassword
*						&$Challenge
* return	: SECUOTP_ERROR_SUCCESS--succeed		
*						SECUOTP_ERROR_CHALLENGE--challenge
*						others failed						
******************************************************************/
function secuotp_auth($sUsername, $sPassword, &$Challenge)
{
	if(!isset($sUsername) || !isset($sPassword) || '' === $sUsername)//invalid params
	{
			return SECUOTP_ERROR_INVALID_PARAM;
	}
	else//process user authentication
	{
		global $dbconfig, $srvconfig;
		$mydb = new mydb();//creat mydb object
		
		//connect to database
		if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
		{
			return SECUOTP_ERROR_CONNECTDBFAILED;
		}
		//inquiry user information
		$sql = "select serialnum, islocked, isdeleted, pin, authtype, preusedate, failaccum from userinfo where username='$sUsername'";
		
		if(!($res = $mydb->query($sql)))
		{
			$mydb->close();
			return SECUOTP_ERROR_SQLEXFAILED;//sql statement error
		}
		if(!($re = $mydb->fetch_assoc($res)))
		{
			$mydb->close();
			return SECUOTP_ERROR_NORELATEITEM;
		}
		
		$serialnum = $re['serialnum'];
		$islocked = $re['islocked'];
		$isdeleted = $re['isdeleted'];
		$pin = $re['pin'];
		$authtype = $re['authtype'];
		$preusedate = $re['preusedate'];
		$failaccum = $re['failaccum'];
		
		//check the user status
		if(1 === intval($isdeleted))
		{
			$mydb->close();
			return SECUOTP_ERROR_USERREGLOST;//user registered lost
		}
		if(1 == intval($islocked))//user been locked
		{
			//unlock or not
			if((strtotime(gmdate('Y-m-d H:i:s')) - strtotime($preusedate)) < $srvconfig['srv_lockinterval']*60)
			{
				//update operation time
				$sql = "update userinfo set preusedate="._date_convert(gmdate('Y-m-d H:i:s'))." where username='$sUsername'";
				if(!($res = $mydb->query($sql)))
				{
					$mydb->close();	
				}
				return SECUOTP_ERROR_USERLOCKED;
			}
			else//unlock the user
			{
				$sql = "update userinfo set preusedate="._date_convert(gmdate('Y-m-d H:i:s')).", islocked=0 where username='$sUsername'";
				if(!($res = $mydb->query($sql)))
				{
					$mydb->close();	
					return SECUOTP_ERROR_UNLOCK_FAILED;
				}
			}
		}
		else//user is useable
		{
			$sql = "update userinfo set preusedate="._date_convert(gmdate('Y-m-d H:i:s'))." where username='$sUsername'";
			if(!($res = $mydb->query($sql)))
			{
				$mydb->close();	
				return SECUOTP_ERROR_UPDATEUSEDATE_FAILED;
			}
		}
		//get user correspond secret information
		$sql = "select userkey, hcounter, lcounter, tktype, predate, state, domain, diglen, authwnd, tmstep from keyinfo where serialnum='$serialnum'";
		if(!($res = $mydb->query($sql)))
		{
			$mydb->close();
			return SECUOTP_ERROR_SQLEXFAILED;
		}
		if(!($re = $mydb->fetch_assoc($res)))
		{
			$mydb->close();
			return SECUOTP_ERROR_NORELATEITEM;	
		}
		
		$userkey = $re['userkey'];
		$hcounter = $re['hcounter'];
		$lcounter = $re['lcounter'];
		$tktype = $re['tktype'];
		$predate = $re['predate'];
		$state = $re['state'];
		//$domain = $re['domain'];
		$diglen = $re['diglen'];
		$authwnd_t = $re['authwnd'];
		$tmstep = $re['tmstep'];
		//authenticate user from here
		if(SECU200 == $tktype)//time based
		{
			//reset counter
			$tm_crt = floor((strtotime(gmdate('Y-m-d H:i:s')) - strtotime($predate))/$tmstep);
			//if the increase counter caused by time larger than half of authentication window size
			// then revise the counter
			if($tm_crt > floor($authwnd_t/2))
			{
				$tm_crt -= floor($authwnd_t/2);
				//
				if(0xffffffff > $hcounter)//carry not need
				{
					if(0xffffffff - $lcounter >= $tm_crt)
					{
						$lcounter += $tm_crt;	
					}
					else
					{
							$hcounter += 1;
							$lcounter = $tm_crt - (0xffffffff - $lcounter);
					}
				}
				else//carry need
				{
					if(0xffffffff - $lcounter >= $tm_crt)
					{
						$lcounter += $tm_crt;
					}
					else
					{
						$hcounter = 0;
						$lcounter = $tm_crt - (0xffffffff - $lcounter);
					}
				}
			}
		}
		else if(SECU300 == $tktype)//challenge-response
		{
			//check validation of the challenge word
			if((0 == $hcounter) || ((strtotime(gmdate('Y-m-d H:i:s')) - strtotime($predate)) > $srvconfig['srv_chgword_livetm']*60))
			{
				//create challenge word and update userinfo in database
				$Challenge = (rand()%9999+1)*1000 + (rand()%9999+1);
				$sql = "update keyinfo set hcounter=1, lcounter=$Challenge, predate="._date_convert(gmdate('Y-m-d H:i:s'))." where serialnum='$serialnum'";
				if(!($res = $mydb->query($sql)))
				{
					$mydb->close();
					return SECUOTP_ERROR_UPCHALLENGE_FAILED;
				}
				return SECUOTP_ERROR_CHALLENGE;
			}
			else
			{
				$hcounter = 0;	
			}
		}
		else if(SECU100 != $tktype)//
		{
			return SECUOTP_ERROR_UNKNOWTKTYPE;
		}
		//authentication from here
		$authwnd = 1;//set authentication window size
		switch($tktype)
		{
			case SECU300:
				break;
			case SECU200:
				$authwnd = (isset($srvconfig['srv_authwnd'][1]) && ($srvconfig['srv_authwnd'][1] < $authwnd_t) ? $srvconfig['srv_authwnd'][1]:$authwnd_t);
				break;
			case SECU100:
				$authwnd = (isset($srvconfig['srv_authwnd'][0]) && ($srvconfig['srv_authwnd'][0] < $authwnd_t) ? $srvconfig['srv_authwnd'][0]:$authwnd_t);
				break;
			default:
				return SECUOTP_ERROR_UNKNOWTKTYPE;
		}
		//
		$ret = secu_userauth($sPassword, $userkey, $hcounter, $lcounter, $authtype, $pin, $diglen, $authwnd);
		if(-1 === $ret)//authentication failed
		{
			//lock user if failaccum is reach the max value
			if($failaccum < $srvconfig['srv_maxfailaccum'])
			{//update failaccum
					++$failaccum;
					
					$sql = "update userinfo set failaccum=$failaccum, preusedate="._date_convert(gmdate('Y-m-d H:i:s'))." where username='$sUsername'";
			}
			else
			{
					$sql = "update userinfo set islocked=1, failaccum=0, preusedate="._date_convert(gmdate('Y-m-d H:i:s'))." where username='$sUsername'";
			}
			@$mydb->query($sql);
			if(SECU300 == $tktype)
			{
				$sql = "update keyinfo set hcounter=0, lcounter=0, predate="._date_convert(gmdate('Y-m-d H:i:s'))." where serialnum='$serialnum'";
				$mydb->query($sql);
			}
			return SECUOTP_ERROR_INVALID_PASSWORD;
		}
		else//if authentication succeed, then update user's information
		{
			if(SECU300 == $tktype)//challenge response based token
			{
				$hcounter = 0;
				$lcounter = 0;
			}
			$sql = "update keyinfo set hcounter=$hcounter, lcounter=$lcounter, predate="._date_convert(gmdate('Y-m-d H:i:s'))." where serialnum='$serialnum'";
			if(!($res = $mydb->query($sql)))
			{
				return SECUOTP_ERROR_UPDATEKEYINFO_FAILED;
			}
			$sql = "update userinfo set islocked=0, failaccum=0, preusedate="._date_convert(gmdate('Y-m-d H:i:s'))." where username='$sUsername'";
			$mydb->query($sql);
			$mydb->close();
			return SECUOTP_ERROR_SUCCESS;
		}
	}
}

/***********************************************************
*	function: secuotp_synchronize
*	params:		$sUsername		-- username
*						$sOtp1				-- the first otp
*						$sOtp2				-- the second otp
* return:		SECUOTP_ERROR_SUCCESS--succeed others--failed
************************************************************/
function secuotp_synchronize($sUsername, $sOtp1, $sOtp2)
{
	if(!isset($sUsername) || !isset($sOtp1) || !isset($sOtp2)
		|| "" === $sOtp1 || "" === $sOtp2 || "" === $sUsername)
	{
		return SECUOTP_ERROR_INVALID_PARAM;	//arguments invalid
	}
	else
	{
		global $dbconfig, $srvconfig;
		$mydb = new mydb();//creat mydb object
		
		//connect to database
		if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
		{
			return SECUOTP_ERROR_CONNECTDBFAILED;
		}
		$sql = "select serialnum, isdeleted from userinfo where username='$sUsername'";
		if(!($res=$mydb->query($sql)))
		{
			$mydb->close();
			return SECUOTP_ERROR_SQLEXFAILED;	
		}
		if(!($re = $mydb->fetch_assoc($res)))//fetch item
		{
			$mydb->close();
			return SECUOTP_ERROR_NORELATEITEM;
		}
		if(1 === intval($re['isdeleted']))
		{
			$mydb->close();
			return SECUOTP_ERROR_USERREGLOST;//user registered lost
		}
		$serialnum = $re['serialnum'];//get serialnum
		$sql = "select userkey, hcounter, lcounter, tktype, predate, state, diglen, authwnd, tmstep from keyinfo where serialnum='$serialnum'";
		if(!($res = $mydb->query($sql)))//sql statement execute failed
		{
			$mydb->close();
			return SECUOTP_ERROR_SQLEXFAILED;
		}
		if(!($re=$mydb->fetch_assoc($res)))
		{
			$mydb->close();
			return SECUOTP_ERROR_NORELATEITEM;
		}
		//get information
		$userkey = $re['userkey'];
		$hcounter = $re['hcounter'];
		$lcounter = $re['lcounter'];
		$tktype = $re['tktype'];
		$predate = $re['predate'];
		$state = $re['state'];
		$diglen = $re['diglen'];
		$authwnd = $re['authwnd'];
		$tmstep = $re['tmstep'];
		//get information
		if(SECU300 === intval($tktype))
		{
			//challenge response based token need not synchronize
			$mydb->close();
			return SECUOTP_ERROR_NOTNEEDSYNCHRONIZE;
		}
		if(SECU200 === intval($tktype))//time-based token revise counter
		{
			//reset counter
			$tm_crt = floor((strtotime(gmdate('Y-m-d H:i:s')) - strtotime($predate))/$tmstep);
			//if the increase counter caused by time larger than half of authentication window size
			// then revise the counter
			if($tm_crt > floor($srvconfig['srv_syncwnd'][1]/2))
			{
				$tm_crt -= floor($srvconfig['srv_syncwnd'][1]/2);
				//
				if(0xffffffff > $hcounter)//carry not need
				{
					if(0xffffffff - $lcounter >= $tm_crt)
					{
						$lcounter += $tm_crt;	
					}
					else
					{
							$hcounter += 1;
							$lcounter = $tm_crt - (0xffffffff - $lcounter);
					}
				}
				else//carry need
				{
					if(0xffffffff - $lcounter >= $tm_crt)
					{
						$lcounter += $tm_crt;
					}
					else
					{
						$hcounter = 0;
						$lcounter = $tm_crt - (0xffffffff - $lcounter);
					}
				}
			}
		}
		//synchronize from here
		//set synchronize wndsize
		$synwnd = $srvconfig['srv_syncwnd'][0];
		if(SECU200 === intval($tktype))
		{
			$synwnd = $srvconfig['srv_syncwnd'][1];
		}
		$ret = secu_user_synchronize($sOtp1, $sOtp2, $userkey, $hcounter, $lcounter, $diglen, $synwnd);
		if(-1 === $ret)
		{
			$mydb->close();
			return SECUOTP_ERROR_SYNCHRONIZE_FAILED;
		}
		//update counter
		else
		{
			$sql = "update keyinfo set hcounter=$hcounter, lcounter=$lcounter, predate="._date_convert(gmdate('Y-m-d H:i:s'))." where serialnum='$serialnum'";
			if(!($res = $mydb->query($sql)))
			{
				$mydb->close();
				return SECUOTP_ERROR_UPDATEKEYINFO_FAILED;
			}
			$mydb->close();
			return SECUOTP_ERROR_SUCCESS;
		}
	}
}

/************************************************************
* function: secuotp_setuserpin
*	params:		$sUsername -- username
*						$sPin			 --	pin for user
* remark:	  set pin for user
*************************************************************/
function secuotp_setuserpin($sUsername, $sPin)
{
	if(!isset($sUsername) || !isset($sPin) || "" === $sUsername)
	{
		return SECUOTP_ERROR_INVALID_PARAM;	
	}
	global $dbconfig, $srvconfig;
	$mydb = new mydb();//creat mydb object
		
	//connect to database
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}
	$sql = "select count(*) from userinfo where username='$sUsername'";
	if(!($res = $mydb->query($sql)))//check user existance
	{
		$mydb->close();
		return SECUOTP_ERROR_GETUSERINFO_FAILED;
	}
	if(!($re = $mydb->fetch_row($res)) || 0 === intval($re[0]))
	{
		$mydb->close();
		return SECUOTP_ERROR_NORELATEITEM;	
	}//check user existance end
	$sql = "update userinfo set pin='$sPin' where username='$sUsername'";
	if(!($ret = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_SETUSERPIN_FAILED;
	}
	
	$mydb->close();
	return SECUOTP_ERROR_SUCCESS;
}

/*********************************************************
*	function: secuotp_resetpin
*	params:		$sUsername
*						$sOldpin
*						$sNewpin
*	return:		SECUOTP_ERROR_SUCCESS--success others--failed
***********************************************************/
function secuotp_resetpin($sUsername, $sOldpin, $sNewpin)
{
	if(!isset($sUsername) || "" === $sUsername 
		|| !isset($sOldpin) || "" === $sOldpin 
		|| !isset($sNewpin) || "" === $sNewpin)
	{
		return SECUOTP_ERROR_INVALID_PARAM;
	}
	else
	{
		global $dbconfig, $srvconfig;
		$mydb = new mydb();//creat mydb object
		
		//connect to database
		if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
		{
			return SECUOTP_ERROR_CONNECTDBFAILED;
		}
		//
		$sql = "select pin from userinfo where username='$sUsername'";
		if(!($res = $mydb->query($sql)))
		{
			$mydb->close();
			return SECUOTP_ERROR_SQLEXFAILED;
		}
		if(!($re = $mydb->fetch_assoc($res)))//fetch result
		{
			$mydb->close();
			return SECUOTP_ERROR_NORELATEITEM;	
		}
		$oldpin = $re['pin'];
		if($oldpin !== $sOldpin)
		{
			$mydb->close();
			return SECUOTP_ERROR_INVALID_OLDPWD;	
		}
		$sql = "update userinfo set pin='$sNewpin' where username='$sUsername'";
		if(!($ret = $mydb->query($sql)))
		{
			$mydb->close();
			return SECUOTP_ERROR_UPDATEPIN_FAILED;
		}
		return SECUOTP_ERROR_SUCCESS;
	}
}
/******************************************************
*	function: secuotp_setauthtype
*	params:		$sUsername	-- username
*						$nAuthtype	-- authentication type
*	return:		SECUOTP_ERROR_SUCCESS--succeed  others--failed
******************************************************/
function secuotp_setauthtype($sUsername, $nAuthtype)
{
	if(!isset($sUsername) || !isset($nAuthtype) || "" === $sUsername)//username invald
	{
		return SECUOTP_ERROR_INVALID_PARAM;
	}
	if(1 !== intval($nAuthtype) && 2 !== intval($nAuthtype))//authentication type unknown
	{
		return SECUOTP_ERROR_INVALID_AUTHTYPE;
	}
	else//set user's authentication type
	{
		global $dbconfig, $srvconfig;
		$mydb = new mydb();//creat mydb object
		//connect to database
		if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
		{
			return SECUOTP_ERROR_CONNECTDBFAILED;
		}
		//set authentication type
		$sql = "update userinfo set authtype=$nAuthtype where username='$sUsername'";
		if(!($ret = $mydb->query($sql)))
		{
			$mydb->close();
			return SECUOTP_ERROR_UPDATEAUTHTYPE_FAILED;	
		}
		$mydb->close();
		return SECUOTP_ERROR_SUCCESS;
	}
}

/*********************************************************************
* function: secuotp_adduser
* params:		$sUsername	--username (max length:20)
*						$sUserid		--user's identity code(max length:20)
*						$sContacttel --phone number(max length:20)
*						$sSerialnum		--serialnum on token(max length:20)
*						$sRemark			--remark(max length:260)
*						$sEmail				--email(max length:20)
*						$sDomain			--user domain(reserved, always use "")
*						$sPin					--user's static PIN(max length:20)
*						$sPreusedate	--use current date time if a null string given
*	return:	SECUOTP_ERROR_SUCCESS--succeed others--failed
************************************************************************/
function secuotp_adduser($sUsername, $sUserid, $sContacttel, $sSerialnum,
													$sRemark, $sEmail, $sDomain, $sPin, $sPreusedate, $nAuthtype
													)
{
	//arguments validation check
	if(!isset($sUsername) || "" === $sUsername 
		|| !isset($sUserid) || "" === $sUserid
		|| !isset($sContacttel) || "" === $sContacttel 
		|| !isset($sSerialnum) || "" === $sSerialnum
		|| !isset($sEmail) || "" === $sEmail	
		|| !isset($sPin) || "" === $sPin	
		)
	{
		return SECUOTP_ERROR_INVALID_PARAM;		
	}
	if(!eregi("^([a-z0-9_]|\\-|\\.)+@(([a-z0-9_]|\\-)+\\.)+[a-z]{2,4}$",$sEmail))
	{
		return ;
	}
	if(1 !== intval($nAuthtype) && 2 != intval($nAuthtype))//authentication type check
	{
		return SECUOTP_ERROR_INVALID_AUTHTYPE;
	}
	//check preusedate
	if("" === $sPreusedate)
	{
		$sPreusedate = gmdate('Y-m-d H:i:s');
	}
	//add user here
	global $dbconfig, $srvconfig;
	$mydb = new mydb();//creat mydb object
	//connect to database
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}
	//check user and token existance
	$sql = "select count(username) from userinfo where username='$sUsername'";
	if(!($res = $mydb->query($sql)))//inquery user existance
	{
		$mydb->close();
		return SECUOTP_ERROR_SQLEXFAILED;
	}
	if(!($re = $mydb->fetch_row($res)))
	{
		$mydb->close();
		return SECUOTP_ERROR_GETUSERINFO_FAILED;	
	}
	if($re[0] > 0)
	{
		$mydb->close();
		return SECUOTP_ERROR_USEREXIST;	
	}
	//check token validation
	$sql = "select state from keyinfo where serialnum='$sSerialnum'";
	if(!($res = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_GETUSERINFO_FAILED;
	}
	if(!($re = $mydb->fetch_assoc($res)))//get item
	{
		$mydb->close();
		return SECUOTP_ERROR_NORELATEITEM;	
	}
	if(0 !== intval($re['state']))
	{
		$mydb->close();
		return SECUOTP_ERROR_INVALID_TOKEN;
	}
	//user information useable, add user here
	$sql = "insert into userinfo (username, userid, contacttel, preusedate, serialnum, remark, user_email, domain, pin, authtype) ".
					" values('$sUsername', '$sUserid', '$sContacttel', "._date_convert($sPreusedate).", '$sSerialnum', '$sRemark', '$sEmail','$sDomain', ".
					"'$sPin', $nAuthtype)";
	if(!($ret = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_ADDUSER_FAILED;
	}
	//update token status
	$sql = "update keyinfo set state=1 where serialnum='$sSerialnum'";
	if(!($ret = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_UPDATETOKEN_FAILED;	
	}
	$mydb->close();
	return SECUOTP_ERROR_SUCCESS;
}

/****************************************************************
* function: secuotp_deleteuser
*	params:		$sUsername	//name of user to be deleted
*	return:		SECUOTP_ERROR_SUCCESS	--succeed		others --failed
****************************************************************/
function secuotp_deleteuser($sUsername)
{
	if(!isset($sUsername) || "" === $sUsername)
	{
		return SECUOTP_ERROR_INVALID_PARAM;
	}
	global $dbconfig, $srvconfig;
	$mydb = new mydb();//creat mydb object
	//connect to database
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}
	$sql = "select keyinfo.state as status, keyinfo.serialnum as serialnum from userinfo, keyinfo where username='$sUsername' and userinfo.serialnum=keyinfo.serialnum";	
	if(!($res = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_SQLEXFAILED;
	}
	if(!($re = $mydb->fetch_assoc($res)))
	{
		$mydb->close();
		return SECUOTP_ERROR_GETUSERINFO_FAILED;	
	}
	//check the status
	if(1 !== intval($re['status']))
	{
		//token is not in use
		$mydb->close();
		return SECUOTP_ERROR_INVALID_TOKEN;	
	}
	else
	{
		$serialnum = $re['serialnum'];
		$sql = "update keyinfo set state=2 where serialnum='$serialnum'";//set token invalid
		if(!($ret = $mydb->query($sql)))
		{
			$mydb->close();
			return SECUOTP_ERROR_UPDATETOKEN_FAILED;
		}
		//delete user
		$sql = "delete from userinfo where username='$sUsername'";
		if(!($ret = $mydb->query($sql)))
		{
			$mydb->close();
			return SECUOTP_ERROR_DELETEUSER_FAILED;	
		}
		
		$mydb->close();
		return SECUOTP_ERROR_SUCCESS;
	}
}

/*****************************************************************
* function:	secuotp_setuserinvalid
*	params:		$sUsername--username
*						$nValid		--validation status 0--valid 1--invalid
*	return:		SECUOTP_ERROR_SUCCESS--operation succeed others--failed
*****************************************************************/
function secuotp_setuserinvalid($sUsername, $nValid)
{
	if(!isset($sUsername) || !isset($nValid)//params check
		|| "" === $sUsername)
	{
		return SECUOTP_ERROR_INVALID_PARAM;		
	}
	if(0 !== intval($nValid) && 1 !== intval($nValid))
	{
		return SECUOTP_ERROR_INVALID_PARAM;	
	}
	//params check finish
	global $dbconfig, $srvconfig;
	$mydb = new mydb();//creat mydb object
	//connect to database
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}
	$sql = "select count(username) from userinfo where username='$sUsername'";
	if(!($res = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_SQLEXFAILED;	
	}
	if(!($re = $mydb->fetch_row($res)))
	{
		$mydb->close();
		return SECUOTP_ERROR_GETUSERINFO_FAILED;	
	}
	if($re[0] < 0)//no related item 
	{
		$mydb->close();
		return SECUOTP_ERROR_NORELATEITEM;	
	}
	$sql = "update userinfo set isdeleted=$nValid where username='$sUsername'";
	if(!($ret = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_SQLEXFAILED;	
	}
	$mydb->close();
	return SECUOTP_ERROR_SUCCESS;
}

/***************************************************************
* function: secuotp_setuserlock
*	params:		$sUsername--username
*						$nLock--user lock status 0--not locked  1--locked
*	return:		SECUOTP_ERROR_SUCCESS--succeed		others--failed
* remark:	if $nLock is set 1, the user will be locked for 10 minutes
****************************************************************/
function secuotp_setuserlock($sUsername, $nLock)
{//parameters validation check
	if(!isset($sUsername) || !isset($nLock)
		|| ("" === $sUsername) || (0 !== intval($nLock) && 1 !== intval($nLock)))
	{
		return SECUOTP_ERROR_INVALID_PARAM;	
	}
	global $dbconfig, $srvconfig;
	$mydb = new mydb();//creat mydb object
	//connect to database
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}
	//operation begin.
	//
	$sql = "select count(username) from userinfo where username='$sUsername'";
	if(!($res = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_SQLEXFAILED;	
	}
	if(!($re = $mydb->fetch_row($res)))
	{
		$mydb->close();
		return SECUOTP_ERROR_GETUSERINFO_FAILED;	
	}
	if(0 >= intval($re[0]))//no relate item
	{
		$mydb->close();
		return SECUOTP_ERROR_NORELATEITEM;
	}
	//update user's lock status
	$sql = "update userinfo set islocked=$nLock, preusedate="._date_convert(gmdate('Y-m-d H:i:s'))." where username='$sUsername'";
	if(!($re = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_UPLOCKSTATUS_FAILED;
	}
	$mydb->close();
	return SECUOTP_ERROR_SUCCESS;
}

/********************************************************************
* function: secuotp_tokenimport
* params:		$sTokenfile--path of the token file 
*												 that contains the items to be imported
*						$sSecret	--secret for decrypt the token file
* return:		SECUOTP_ERROR_SUCCESS--succeed others--failed
********************************************************************/
function secuotp_tokenimport($sTokenfile, $sSecret, &$sErrinfo)
{
	if(!isset($sTokenfile) || !isset($sSecret)
			|| ("" === $sTokenfile) || "" === $sSecret)//params check
	{
		return SECUOTP_ERROR_INVALID_PARAM;	
	}
	if(!file_exists($sTokenfile))
	{
		return SECUOTP_ERROR_FILENOTEXIST;
	}
	global $dbconfig, $srvconfig;
	
	//connect to database begin.
	$mydb = new mydb();//creat mydb object
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}//connect to database end.
	$aes = new AES();
	$sOutplaintext ="";
	$ret = $aes->decryptFileEx($sTokenfile, $sSecret, $sOutplaintext);
	if(!$ret)
	{
		return SECUOTP_ERROR_AESGETPLAIN_FAILED;	
	}
	//analyses the token string
	//*************************
	//*************************
	
	$tag = "\r\n";
	if(!eregi($tag, $sOutplaintext))
	{
		if(eregi("\n", $sOutplaintext))
		{
			$tag = "\n";	
		}
		else if(eregi("\r", $sOutplaintext))
		{
			$tag = "\r";
		}
		else
		{
			return SECUOTP_ERROR_AESDECRYPT_FAILED;
		}
	}

	$sErrinfo = "";
	$retarr = explode($tag, $sOutplaintext);
	if($retarr[0] === "secu_uniotp")//文件
	{
		//解析令牌信息
		$itemcount = count($retarr);
		for($i = 1; $i < $itemcount; ++$i)
		{
			@list($serialnum,$userkey, $hcounter, $lcounter, $tktype, $predate, $diglen, $authwnd, $tmstep) = explode("|", $retarr[$i]);
			
			//for test
			//echo $serialnum."|".$userkey."|".$hcounter."|".$lcounter."|".$tktype."|".$predate;
			//echo "<br />";
			if(
				!isset($serialnum) || !isset($userkey) || !isset($hcounter) || !isset($lcounter) || !isset($tktype) || !isset($predate)
				|| "" == $serialnum || "" == $userkey || "" == $predate || !($tktype == 1 || $tktype == 2 || $tktype == 3)
				)//parameter validation check
			{
				$sErrinfo .= $retarr[$i];
				$sErrinfo .= "<br>";
			}
			else
			{
				$sql = "select count(*) from keyinfo where serialnum='$serialnum'";
				if(!($res = $mydb->query($sql)))
				{
					$sErrinfo .= $retarr[$i];
					$sErrinfo .= "<br>";
					continue;
				}
				if(!($ret = $mydb->fetch_row($res)))
				{
					$sErrinfo .= $retarr[$i];
					$sErrinfo .= "<br>";
					continue;	
				}
				if($ret[0] > 0)//token already exist
				{
					$sErrinfo .= $retarr[$i];
					$sErrinfo .= "#<br>";
					continue;
				}
				$diglen = isset($diglen) ? $diglen:6;
				$authwnd = isset($authwnd) ? $authwnd:30;
				$tmstep = isset($tmstep) ? $tmstep:60;
				$sql="insert into keyinfo (serialnum,userkey, hcounter, lcounter, tktype, predate, importdate, diglen, authwnd, tmstep) values('$serialnum','$userkey', $hcounter, $lcounter, $tktype, "._date_convert($predate).", "._date_convert(gmdate('Y-m-d H:i:s')).", $diglen, $authwnd, $tmstep)";
				if(!($mydb->query($sql)))
				{
					$sErrinfo .= $retarr[$i];
					$sErrinfo .= "<br>";
				}
			}
		}
		if("" !== $sErrinfo)
		{
			return SECUOTP_ERROR_SUCCESS_WITHINFO;	
		}
		else
		{
			return SECUOTP_ERROR_SUCCESS;	
		}
	}
	else
	{
		return SECUOTP_ERROR_AESDECRYPT_FAILED;
	}
	
}

/******************************************************************************************
* function: secuotp_userimport
*	params:		$sUserfile--path of file that contains user items
*						$sSecret--secret
*	return:		SECUOTP_ERROR_SUCCESS--succeed	others--failed
* remark:		update corresponding token status failed if the error item end with '*', in which case 
*						you should do it manually
******************************************************************************************/
function secuotp_userimport($sUserfile, &$sErrinfo, $sSecret="")
{
	if(!isset($sUserfile) || !isset($sSecret))
	{
		return SECUOTP_ERROR_INVALID_PARAM;
	}
	if(!file_exists($sUserfile))
	{
		return SECUOTP_ERROR_FILENOTEXIST;
	}
	
	global $dbconfig, $srvconfig;
	//connect to database begin.
	$mydb = new mydb();//creat mydb object
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}//connect to database end.
	
	//解析用户信息
	$sOutplaintext = "";
	if(isset($sSecret) && "" != $sSecret)
	{
		$aes = new AES();
		$ret = $aes->decryptFileEx($sUserfile, $sSecret, $sOutplaintext);
		if(!$ret)
		{
			return SECUOTP_ERROR_AESGETPLAIN_FAILED;	
		}
	}
	else
	{
		$sOutplaintext = file_get_contents($sUserfile);
	}
	
	//ensure sepreate tag begin
	$tag = "\r\n";
	if(!eregi($tag, $sOutplaintext))
	{
		if(eregi("\n", $sOutplaintext))
		{
			$tag = "\n";	
		}
		else if(eregi("\r", $sOutplaintext))
		{
			$tag = "\r";
		}
		else
		{
			return SECUOTP_ERROR_AESDECRYPT_FAILED;
		}
	}
	//ensure sepreate tag end
	$sErrinfo = "";
	$retarr = explode($tag, $sOutplaintext);
	$itemcount = count($retarr);
	for($i = 0; $i < $itemcount; ++$i)
	{
		$user_info = explode("|", $retarr[$i]);
		@list($username, $userid, $contacttel, $preusedate, $serialnum, $remark, $user_email, $pin, $authtype) = $user_info;
		//echo "username:".$username." userid:".$userid." contacttel:".$contacttel." preusedate:".$preusedate." serialnum:".$serialnum." remark:".$remark." user_email:".$user_email." pin:".$pin." authtype:".$authtype."<br>";
		if(
			!isset($username) || !isset($userid) || !isset($contacttel) || !isset($preusedate) || !isset($serialnum) || !isset($remark)
			|| !isset($user_email) || !isset($pin) || !isset($authtype) || "" == $username || "" == $userid || "" == $preusedate || "" == $serialnum
			|| "" == $authtype
			)//parameters check
		{
			$sErrinfo .= $retarr[$i];
			$sErrinfo .= "<br>";
		}
		else
		{
			//insert useritem from here
			//to ensure validation of username and serialnum
			$sql = "select count(*) from userinfo where username='$username'";
			if(!($res = $mydb->query($sql)))
			{
				$sErrinfo .= $retarr[$i];
				$sErrinfo .= "<br>";	
				continue;
			}
			else
			{
				if(!($re = $mydb->fetch_row($res)))
				{
					$sErrinfo .= $retarr[$i];
					$sErrinfo .= "<br>";	
					continue;
				}
				else
				{
					if($re[0] > 0)//username already exist
					{
						$sErrinfo .= $retarr[$i];
						$sErrinfo .= "#<br>";	
						continue;
					}
					else//username valid
					{
						//check token validation
						$sql = "select count(*) from keyinfo where serialnum='$serialnum' and state=0";
						if(!($res = $mydb->query($sql)))//
						{
							$sErrinfo .= $retarr[$i];
							$sErrinfo .= "<br>";	
							continue;
						}
						else
						{
							if(!($re = $mydb->fetch_row($res)))
							{
								$sErrinfo .= $retarr[$i];
								$sErrinfo .= "<br>";	
								continue;	
							}
							else
							{
								if($re[0] > 0)//useable token
								{
									$sql = "insert into userinfo (username, userid, contacttel, serialnum, remark, user_email, pin, authtype, preusedate) ";
									$sql .= "values('$username','$userid','$contacttel','$serialnum','$remark', '$user_email', '$pin', $authtype, "._date_convert($preusedate).")";
									if(!($mydb->query($sql)))
									{
										$sErrinfo .= $retarr[$i];
										$sErrinfo .= "<br>";	
										continue;	
									}
									else
									{
										$sql = "update keyinfo set state=1 where serialnum='$serialnum'";
										if(!($re = $mydb->query($sql)))
										{
											$sErrinfo .= $retarr[$i];
											$sErrinfo .= "*<br>";	
											continue;		
										}
									}
								}
								else
								{
									$sErrinfo .= $retarr[$i];
									$sErrinfo .= "$<br>";	
									continue;	
								}
							}
						}
					}
				}
			}
		}
	}
	if("" == $sErrinfo)
	{
		return SECUOTP_ERROR_SUCCESS;
	}
	else
	{
		return SECUOTP_ERROR_SUCCESS_WITHINFO;	
	}
}


/***************************************************************************
* function: secuotp_tokendelete
* params:		$sTokenserialnum
*	return:		SECUOTP_ERROR_SUCCESS--succeed		others--failed
****************************************************************************/
function secuotp_tokendelete($sTokenserialnum)
{
	if(!isset($sTokenserialnum) || ("" === $sTokenserialnum))
	{
		return SECUOTP_ERROR_INVALID_PARAM;	
	}
	
	global $dbconfig, $srvconfig;
	//connect to database begin.
	$mydb = new mydb();//creat mydb object
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}//connect to database end.
	$sql = "select state from keyinfo where serialnum='$sTokenserialnum'";
	if(!($res = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_GETUSERINFO_FAILED;
	}
	if(!($re = $mydb->fetch_assoc($res)))
	{
		$mydb->close();
		return SECUOTP_ERROR_NORELATEITEM;
	}
	if(1 === intval($re['state']))
	{
		//token is in use
		$mydb->close();
		return SECUOTP_ERROR_TOKENINUSE;	
	}
	//delete token from db
	$sql = "delete from keyinfo where serialnum='$sTokenserialnum'";
	if(!($re = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_DELETETOKEN_FAILED;
	}
	$mydb->close();
	return SECUOTP_ERROR_SUCCESS;
}

/**************************************************************
* function: secuotp_makelog
* params:		$nLoglev--log level
*						$sOperator--operator name
*						$nOptype--operation type
*						$sContent--log content
* return:		SECUOTP_ERROR_SUCCESS--succeed		others--failed
**************************************************************/
function secuotp_makelog($nLoglev, $sOperator, $nOptype, $sContent, $sSrvip)
{
	if(!isset($nLoglev) || !isset($sOperator) ||!isset($nOptype)
		|| !isset($sContent) || !isset($sSrvip))
	{
		return SECUOTP_ERROR_INVALID_PARAM;	
	}
	if((SECUOTP_PRI_SUPER != $nLoglev) && (SECUOTP_PRI_ADMIN != $nLoglev) && (SECUOTP_PRI_OPERATOR != $nLoglev) && (SECUOTP_PRI_USER != $nLoglev))
	{
		return SECUOTP_ERROR_INVALIDLOGLEV;	
	}
	global $dbconfig, $srvconfig;
	//connect to database begin.
	$mydb = new mydb();//creat mydb object
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}//connect to database end.
	
	if(AUTH === intval($nOptype))
	{
		if("" === $sSrvip)
		{
			return SECUOTP_ERROR_INVALID_PARAM;
		}
		$sql = "insert into commonloginfo (optime, operator, loglev, optype, remark, remoteip) values("._date_convert(gmdate('Y-m-d H:i:s')).", '$sOperator', $nLoglev, $nOptype, '$sContent', '$sSrvip')";
	}
	else
	{
		$sql = "insert into sysloginfo (optime, operator, loglev, optype, remark) values("._date_convert(gmdate('Y-m-d H:i:s')).", '$sOperator', $nLoglev, $nOptype, '$sContent')";
	}

	if(!($ret = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_SQLEXFAILED;	
	}
	$mydb->close();
	return SECUOTP_ERROR_SUCCESS;
}
/*********************************************************************
* function: secuotp_rebind
*	params:		$sUsername -- name of user to be rebind
*						$sNewserialnum -- new serialnum for rebind operation
*	return 		SECUOTP_ERROR_SUCCESS -- succeed	others -- failed
********************************************************************/
function secuotp_rebind($sUsername, $sNewserialnum)
{
	//params validation check
	if(!isset($sUsername) || !isset($sNewserialnum)
			|| "" === $sUsername || "" === $sNewserialnum)
	{
		return SECUOTP_ERROR_INVALID_PARAM;
	}
	global $dbconfig, $srvconfig;
	//connect to database begin.
	$mydb = new mydb();//creat mydb object
	if(!@($mydb->connect($dbconfig['db_host'], $dbconfig['db_user'], $dbconfig['db_password'], $dbconfig['db_port'], $dbconfig['db_dbname'], $dbconfig['db_characterset'])))
	{
		return SECUOTP_ERROR_CONNECTDBFAILED;
	}//connect to database end.
	
	//to ensure user's existence
	$sql = "select isdeleted, serialnum from userinfo where username='$sUsername'";
	if(!($res = $mydb->query($sql)))//
	{
		$mydb->close();
		return SECUOTP_ERROR_GETUSERINFO_FAILED;
	}
	if(!($ret = $mydb->fetch_assoc($res)))
	{
		$mydb->close();
		return SECUOTP_ERROR_NORELATEITEM;	
	}
	$isdeleted = $ret['isdeleted'];
	$oldserialnum = $ret['serialnum'];
	if($isdeleted)//user not useable
	{
		$mydb->close();
		return SECUOTP_ERROR_USERREGLOST;
	}
	//check validation status of token to be bind to the user
	$sql = "select state from keyinfo where serialnum='$sNewserialnum'";
	if(!($res = $mydb->query($sql)))//sql statement execute failed
	{
		$mydb->close();
		return SECUOTP_ERROR_GETTOKENSTATE_FAILED;
	}
	if(!($ret = $mydb->fetch_assoc($res)))//fetch row failed
	{
		$mydb->close();
		return SECUOTP_ERROR_GETTOKENSTATE_FAILED;
	}
	if(1 == $ret['state'])
	{
		$mydb->close();
		return SECUOTP_ERROR_INVALID_TOKEN;	
	}
	//username and token valid then update user and token status information
	
	$sql = "update userinfo set serialnum='$sNewserialnum' where username='$sUsername'";
	if(!($ret = $mydb->query($sql)))//update user's token information failed
	{
		$mydb->close();
		return SECUOTP_ERROR_UPDATEUSERBINDINFO_FAILED;
	}
	
	//set token state
	$sql = "update keyinfo set state=1 where serialnum='$sNewserialnum'";
	if(!($ret = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_UPDATETOKEN_FAILED;	
	}
	$sql = "update keyinfo set state=2 where serialnum='$oldserialnum'";
	if(!($ret = $mydb->query($sql)))
	{
		$mydb->close();
		return SECUOTP_ERROR_UPDATETOKEN_FAILED;	
	}
	$mydb->close();
	return SECUOTP_ERROR_SUCCESS;
}
?>