Skip to content
Snippets Groups Projects
session.php 7.6 KiB
Newer Older
  • Learn to ignore specific revisions
  • <?
    // To use:
    // include_once "session.php"
    // $mysession = new Session;
    // 
    // $mysession->loggedin is TRUE if they have logged in
    //
    // other attributes are :
    // username   - the username they logged in with
    // fullname   - whatever full name we know for them
    // last   - unix timestamp for their previous page access
    // data   - var/array for persistant data, commit by calling the 'save' method
    
    
    // Session management and authentication mechanism.
    class Session {
    public	$loggedin=FALSE;	// Is this a valid logged in user ?
    public	$username='';		// Username
    public	$fullname;		// Fullname
    public  $email=0;		// Email waiting?
    public  $email_forward;		// Email forwarded?
    public  $groups  =array();	// users groups
    public	$data='';		// Var/array for session persistant data
    public	$token='';		// session identifier
    public	$last='';		// Time of last page request
    private	$timeout = 300;		// Idle timeout limit in minutes
    private	$table = "session";	// session storage table (const)
    private $datahash='';		// hash of data field
    
    	// Create a new session id
    	private function newsession()
    	{
    		global $DB;
    		$try = 0;
    
    		do {
    			$tt=date("D M d H:i:s Y");
    			$ip = $_SERVER['REMOTE_ADDR'];
    			$token = md5("$ip$tt$try");
    			$old = $DB->GetAll("select hash from session where hash=?", array($token));
    		}while ($old);
    		$DB->Execute("insert into session (hash, time, ip) values (?,NOW(),?)", array($token, $ip));
    		setcookie("session", $token, NULL, "/");
    		$this->token = $token;
    		return;
    	}
    
    	// Public Object constructor
    	function __construct()
    	{
    		global $DB;
    		unset($token);
    
    		// The possible form elements
    		$submit = @$_POST['Login'];
    		$logout = @$_POST['Logout'];
    		$session_user = strtolower(@$_POST['session_user']);
    		$session_pass = @$_POST['session_pass'];
    
    		// We havent logged them in yet
    		$this->loggedin = FALSE;
    
    		// Time out any old sessions
    		$DB->Execute("delete from {$this->table} where time < NOW() - '{$this->timeout} minutes'::reltime");
    
    		// Log them out if they ask
    		if ($logout=="Logout") {
    			$this->logout();
    			return;
    		}
    
    		// the possible token data passed from a form
    		if (isset($_REQUEST['token'])) 
    			$token = $_REQUEST['token'];
    
    		// Check if we were handed a specific token identifier
    		// Otherwise use the value from the cookie we gave out
    		if (!isset($token) && isset($_COOKIE['session'])) 
    			$token=@$_COOKIE['session'];
    
    		if (isset($token)) $this->token = $token;
    
    		// Okay, so we still dont have a session id
    		// so issue a new one and go back to core
    		if (!isset($token))  
    		{
    			$this->newsession();
    			return;
    		}
    
    		// Is this a login attempt ?
    		if ($submit != '' && $session_user != '' && $session_pass != '')
    		{
    			$this->session_init($session_user, $session_pass);
    		}
    
    		// Retrieve session information
    		$oldsess=$DB->GetAll("select * from {$this->table} where hash=?", array($this->token));
    
    		if (!$oldsess || count($oldsess) < 1) {
    			$this->errormsg="Session timed out";
    			$this->newsession();
    			return;
    		}
    
    		// Extract detail of session for pass-back
    		$detail = $oldsess[0];
    		$this->data = unserialize((string)$detail['data']);
    		$this->last = strtotime($detail['time']);
    		$this->datahash = md5(serialize($this->data));
    
    		// are we actually logged in, fill in more
    		if ($detail['username']) {
    			// Are we using HTTPS?
    			if (!isset($_SERVER['HTTPS'])) {
    				$this->errormsg = "Insecure Connection";
    				$this->loggedin = FALSE;
    				return;
    			}
    			// User is valid but they're coming from the wrong IP
    			if ($detail['ip'] != $_SERVER['REMOTE_ADDR']) {
    				$this->errormsg = "Your IP address has changed - you have been logged out";
    				$this->logout();
    				return;
    			}
    			$this->username=$detail['username'];
    			$this->fetch_detail($detail['username']);
    			$this->loggedin = TRUE;
    		}
    
    		// update time stamp
    		$DB->Execute( "update {$this->table} set time=NOW() where hash=?", array($this->token));
    	}
    
    	// Public function: Store the session data away in the database
    	public function save( )
    	{
    		global $DB;
    		$newhash = md5(serialize($this->data));
    		if ($newhash == $this->datahash) {
    			// no change in data, dont save
    			return;
    		}
    
    		$DB->Execute("update {$this->table} set data=? where hash=?", array(serialize($this->data),$this->token));
    
    	}
    
    	// Public function: force a logout of the session
    	public function logout( )
    	{
    		global $DB;
    		$DB->Execute("delete from session where hash=?", array($this->token));
    		$this->newsession();
    		$this->loggedin = FALSE;
    	}
    
    	// Fill out any extra details we know about the user
    	private function fetch_detail( $user )
    	{
    		if (!($ldap = @ldap_connect("ldap://localhost"))) {
    			$this->errormsg="LDAP connect failed";
    			return FALSE;
    		}
    		$info = $this->ldap_getuser($ldap, $user);
    		if (!$info) return FALSE;
    
    		ldap_close($ldap);
    
    		// Check the user's email status
    		$mailstat = @stat("/var/spool/mail/".$user);
    		if ($mailstat[size]>0) {
    			if ($mailstat[mtime]>$mailstat[atime]) $this->email = 2;
    			else $this->email = 1;
    		}
    
    		if (file_exists($info['homedirectory'][0]."/.forward")) {
    			$forward = file($info['homedirectory'][0]."/.forward");
    			$this->email_forward = ereg_replace("\n", "", $forward[0]);
    		}
    
    		$this->fullname = $info['cn'][0];
    		$this->groups = $info['grouplist'];
    
    	}
    
    	/* check using mod_auth_externals helper 
    	private function check_pass($user, $pass)
    	{
    
    		if ($fd === FALSE) {
    			$this->errormsg = "Auth system error";
    			return FALSE;
    		}
    
    		fwrite($fd, "$user\n");
    		fwrite($fd, "$pass\n");
    		$ret = pclose($fd);
    		if ($ret == 0) return TRUE;
    
    		$this->autherror = "u='$user' p='$pass' ret=$ret";
    		$this->errormsg = "Invalid Username or Password";
    		return FALSE;
    	}
    	*/
    
    	// Get a users full record from ldap
    	private function ldap_getuser($ldap, $user)
    	{
    		// publically bind to find user
    		if (!($bind=@ldap_bind($ldap, "", ""))) {
    			$this->errormsg="LDAP bind failed";
    			return NULL;
    		}
    		// find the user
    		if (!($search=@ldap_search($ldap, "dc=sucs,dc=org", "(&(uid=$user))"))) {
    			$this->errormsg="LDAP search fail";
    			return NULL;
    		}
    		$n = ldap_count_entries($ldap, $search);
    		if ($n < 1) {
    			$this->errormsg = "Username or Password Incorrect";
    			return NULL;
    		}
    		$info = ldap_get_entries($ldap, $search);
    
    		if (($grpsearch=@ldap_search($ldap, "ou=Group,dc=sucs,dc=org", "memberuid=$user"))) {
    			$gn = ldap_count_entries($ldap,$grpsearch);
    			$gpile = ldap_get_entries($ldap, $grpsearch);
    			$glist=array();
    			for ($i=0;$i<$gn;$i++) {
    				$glist[  $gpile[$i]['cn'][0] ] = $gpile[$i]['gidnumber'][0];
    			}
    			$info[0]['grouplist'] = $glist;
    		}
    		return $info[0];
    	}
    
    	/* check using ldap directly */
    	private function check_pass($user, $pass)
    	{
    		// Open connection
    		if (!($ldap = @ldap_connect("ldap://localhost"))) {
    			$this->errormsg="LDAP connect failed";
    			return FALSE;
    		}
    		$info = $this->ldap_getuser($ldap, $user);
    		if (!$info) return FALSE;
    
    		$real = @ldap_bind($ldap, $info['dn'], $pass);
    
    		ldap_close($ldap);
    		if ($real) return TRUE;
    		$this->errormsg="Username or Password Incorrect";
    		return FALSE;
    
    	}
    
    	// Private function: process login form
    	private function session_init($user, $pass)
    	{
    		global $DB;
    		// Check that this is a valid session start
    		// This prevents replay attacks
    		$sess = $DB->GetAll("select * from {$this->table} where hash=? and username is NULL", array($this->token));
    		if (!$sess || count($sess)<1) {
    			$this->errormsg = "Invalid session, login again.";
    			return;
    		}
    
    		if (!$this->check_pass($user, $pass)) return;
    		$this->username = $user;
    
    		// Update the session, filling in the blanks
    		$DB->Execute("update {$this->table} set username=?, time='NOW()', ip=? where hash=?", array($this->username, $_SERVER['REMOTE_ADDR'], $this->token));
    
    		// Return back to normal session retrieval
    	}
    
    } // end of Class