includes/sessions.php
changeset 229 97ae8e9d5e29
parent 228 b0a4d179be85
child 248 ed13b72b13cc
equal deleted inserted replaced
147:d8156d18ac58 229:97ae8e9d5e29
   360    */
   360    */
   361   
   361   
   362   function start()
   362   function start()
   363   {
   363   {
   364     global $db, $session, $paths, $template, $plugins; // Common objects
   364     global $db, $session, $paths, $template, $plugins; // Common objects
       
   365     global $lang;
   365     if($this->started) return;
   366     if($this->started) return;
   366     $this->started = true;
   367     $this->started = true;
   367     $user = false;
   368     $user = false;
   368     if(isset($_COOKIE['sid']))
   369     if(isset($_COOKIE['sid']))
   369     {
   370     {
   379       {
   380       {
   380         $data = RenderMan::strToPageID($paths->get_pageid_from_url());
   381         $data = RenderMan::strToPageID($paths->get_pageid_from_url());
   381         
   382         
   382         if(!$this->compat && $userdata['account_active'] != 1 && $data[1] != 'Special' && $data[1] != 'Admin')
   383         if(!$this->compat && $userdata['account_active'] != 1 && $data[1] != 'Special' && $data[1] != 'Admin')
   383         {
   384         {
       
   385           $language = intval(getConfig('default_language'));
       
   386           $lang = new Language($language);
       
   387           
   384           $this->logout();
   388           $this->logout();
   385           $a = getConfig('account_activation');
   389           $a = getConfig('account_activation');
   386           switch($a)
   390           switch($a)
   387           {
   391           {
   388             case 'none':
   392             case 'none':
   478             $this->style = $template->default_style;
   482             $this->style = $template->default_style;
   479           }
   483           }
   480         }
   484         }
   481         $user = true;
   485         $user = true;
   482         
   486         
       
   487         // Set language
       
   488         if ( !defined('ENANO_ALLOW_LOAD_NOLANG') )
       
   489         {
       
   490           $lang_id = intval($userdata['user_lang']);
       
   491           $lang = new Language($lang_id);
       
   492         }
       
   493         
   483         if(isset($_REQUEST['auth']) && !$this->sid_super)
   494         if(isset($_REQUEST['auth']) && !$this->sid_super)
   484         {
   495         {
   485           // Now he thinks he's a moderator. Or maybe even an administrator. Let's find out if he's telling the truth.
   496           // Now he thinks he's a moderator. Or maybe even an administrator. Let's find out if he's telling the truth.
   486           if($this->compat)
   497           if($this->compat)
   487           {
   498           {
   545    * @param string $username The username
   556    * @param string $username The username
   546    * @param string $aes_data The encrypted password, hex-encoded
   557    * @param string $aes_data The encrypted password, hex-encoded
   547    * @param string $aes_key The MD5 hash of the encryption key, hex-encoded
   558    * @param string $aes_key The MD5 hash of the encryption key, hex-encoded
   548    * @param string $challenge The 256-bit MD5 challenge string - first 128 bits should be the hash, the last 128 should be the challenge salt
   559    * @param string $challenge The 256-bit MD5 challenge string - first 128 bits should be the hash, the last 128 should be the challenge salt
   549    * @param int $level The privilege level we're authenticating for, defaults to 0
   560    * @param int $level The privilege level we're authenticating for, defaults to 0
       
   561    * @param array $captcha_hash Optional. If we're locked out and the lockout policy is captcha, this should be the identifier for the code.
       
   562    * @param array $captcha_code Optional. If we're locked out and the lockout policy is captcha, this should be the code the user entered.
   550    * @return string 'success' on success, or error string on failure
   563    * @return string 'success' on success, or error string on failure
   551    */
   564    */
   552    
   565    
   553   function login_with_crypto($username, $aes_data, $aes_key, $challenge, $level = USER_LEVEL_MEMBER)
   566   function login_with_crypto($username, $aes_data, $aes_key, $challenge, $level = USER_LEVEL_MEMBER, $captcha_hash = false, $captcha_code = false)
   554   {
   567   {
   555     global $db, $session, $paths, $template, $plugins; // Common objects
   568     global $db, $session, $paths, $template, $plugins; // Common objects
   556     
   569     
   557     $privcache = $this->private_key;
   570     $privcache = $this->private_key;
       
   571 
       
   572     if ( !defined('IN_ENANO_INSTALL') )
       
   573     {
       
   574       // Lockout stuff
       
   575       $threshold = ( $_ = getConfig('lockout_threshold') ) ? intval($_) : 5;
       
   576       $duration  = ( $_ = getConfig('lockout_duration') ) ? intval($_) : 15;
       
   577       // convert to minutes
       
   578       $duration  = $duration * 60;
       
   579       $policy = ( $x = getConfig('lockout_policy') && in_array(getConfig('lockout_policy'), array('lockout', 'disable', 'captcha')) ) ? getConfig('lockout_policy') : 'lockout';
       
   580       if ( $policy == 'captcha' && $captcha_hash && $captcha_code )
       
   581       {
       
   582         // policy is captcha -- check if it's correct, and if so, bypass lockout check
       
   583         $real_code = $this->get_captcha($captcha_hash);
       
   584       }
       
   585       if ( $policy != 'disable' && !( $policy == 'captcha' && isset($real_code) && $real_code == $captcha_code ) )
       
   586       {
       
   587         $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
       
   588         $timestamp_cutoff = time() - $duration;
       
   589         $q = $this->sql('SELECT timestamp FROM '.table_prefix.'lockout WHERE timestamp > ' . $timestamp_cutoff . ' AND ipaddr = \'' . $ipaddr . '\' ORDER BY timestamp DESC;');
       
   590         $fails = $db->numrows();
       
   591         if ( $fails >= $threshold )
       
   592         {
       
   593           // ooh boy, somebody's in trouble ;-)
       
   594           $row = $db->fetchrow();
       
   595           $db->free_result();
       
   596           return array(
       
   597               'success' => false,
       
   598               'error' => 'locked_out',
       
   599               'lockout_threshold' => $threshold,
       
   600               'lockout_duration' => ( $duration / 60 ),
       
   601               'lockout_fails' => $fails,
       
   602               'lockout_policy' => $policy,
       
   603               'time_rem' => ( $duration / 60 ) - round( ( time() - $row['timestamp'] ) / 60 ),
       
   604               'lockout_last_time' => $row['timestamp']
       
   605             );
       
   606         }
       
   607         $db->free_result();
       
   608       }
       
   609     }
   558     
   610     
   559     // Instanciate the Rijndael encryption object
   611     // Instanciate the Rijndael encryption object
   560     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   612     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   561     
   613     
   562     // Fetch our decryption key
   614     // Fetch our decryption key
   563     
   615     
   564     $aes_key = $this->fetch_public_key($aes_key);
   616     $aes_key = $this->fetch_public_key($aes_key);
   565     if(!$aes_key)
   617     if(!$aes_key)
   566       return 'Couldn\'t look up public key "'.$aes_key.'" for decryption';
   618       return array(
       
   619         'success' => false,
       
   620         'error' => 'key_not_found'
       
   621         );
   567     
   622     
   568     // Convert the key to a binary string
   623     // Convert the key to a binary string
   569     $bin_key = hexdecode($aes_key);
   624     $bin_key = hexdecode($aes_key);
   570     
   625     
   571     if(strlen($bin_key) != AES_BITS / 8)
   626     if(strlen($bin_key) != AES_BITS / 8)
   572       return 'The decryption key is the wrong length';
   627       return array(
       
   628         'success' => false,
       
   629         'error' => 'key_wrong_length'
       
   630         );
   573     
   631     
   574     // Decrypt our password
   632     // Decrypt our password
   575     $password = $aes->decrypt($aes_data, $bin_key, ENC_HEX);
   633     $password = $aes->decrypt($aes_data, $bin_key, ENC_HEX);
   576     
   634     
   577     // Initialize our success switch
   635     // Initialize our success switch
   583     
   641     
   584     // Select the user data from the table, and decrypt that so we can verify the password
   642     // Select the user data from the table, and decrypt that so we can verify the password
   585     $this->sql('SELECT password,old_encryption,user_id,user_level,theme,style,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$db_username_lower.'\' OR username=\'' . $db_username . '\';');
   643     $this->sql('SELECT password,old_encryption,user_id,user_level,theme,style,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$db_username_lower.'\' OR username=\'' . $db_username . '\';');
   586     if($db->numrows() < 1)
   644     if($db->numrows() < 1)
   587     {
   645     {
   588       return "The username and/or password is incorrect.\n$db->latest_query";
       
   589       // This wasn't logged in <1.0.2, dunno how it slipped through
   646       // This wasn't logged in <1.0.2, dunno how it slipped through
   590       if($level > USER_LEVEL_MEMBER)
   647       if($level > USER_LEVEL_MEMBER)
   591         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
   648         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
   592       else
   649       else
   593         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
   650         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
   594         
   651     
       
   652       if ( $policy != 'disable' && !defined('IN_ENANO_INSTALL') )
       
   653       {
       
   654         $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
       
   655         // increment fail count
       
   656         $this->sql('INSERT INTO '.table_prefix.'lockout(ipaddr, timestamp, action) VALUES(\'' . $ipaddr . '\', UNIX_TIMESTAMP(), \'credential\');');
       
   657         $fails++;
       
   658         // ooh boy, somebody's in trouble ;-)
       
   659         return array(
       
   660             'success' => false,
       
   661             'error' => ( $fails >= $threshold ) ? 'locked_out' : 'invalid_credentials',
       
   662             'lockout_threshold' => $threshold,
       
   663             'lockout_duration' => ( $duration / 60 ),
       
   664             'lockout_fails' => $fails,
       
   665             'time_rem' => ( $duration / 60 ),
       
   666             'lockout_policy' => $policy
       
   667           );
       
   668       }
       
   669       
       
   670       return array(
       
   671           'success' => false,
       
   672           'error' => 'invalid_credentials'
       
   673         );
   595     }
   674     }
   596     $row = $db->fetchrow();
   675     $row = $db->fetchrow();
   597     
   676     
   598     // Check to see if we're logging in using a temporary password
   677     // Check to see if we're logging in using a temporary password
   599     
   678     
   640       }
   719       }
   641     }
   720     }
   642     if($success)
   721     if($success)
   643     {
   722     {
   644       if($level > $row['user_level'])
   723       if($level > $row['user_level'])
   645         return 'You are not authorized for this level of access.';
   724         return array(
       
   725           'success' => false,
       
   726           'error' => 'too_big_for_britches'
       
   727         );
   646       
   728       
   647       $sess = $this->register_session(intval($row['user_id']), $username, $password, $level);
   729       $sess = $this->register_session(intval($row['user_id']), $username, $password, $level);
   648       if($sess)
   730       if($sess)
   649       {
   731       {
   650         $this->username = $username;
   732         $this->username = $username;
   660         $code = $plugins->setHook('login_success');
   742         $code = $plugins->setHook('login_success');
   661         foreach ( $code as $cmd )
   743         foreach ( $code as $cmd )
   662         {
   744         {
   663           eval($cmd);
   745           eval($cmd);
   664         }
   746         }
   665         return 'success';
   747         return array(
       
   748           'success' => true
       
   749         );
   666       }
   750       }
   667       else
   751       else
   668         return 'Your login credentials were correct, but an internal error occurred while registering the session key in the database.';
   752         return array(
       
   753           'success' => false,
       
   754           'error' => 'backend_fail'
       
   755         );
   669     }
   756     }
   670     else
   757     else
   671     {
   758     {
   672       if($level > USER_LEVEL_MEMBER)
   759       if($level > USER_LEVEL_MEMBER)
   673         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
   760         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
   674       else
   761       else
   675         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
   762         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
   676         
   763         
   677       return 'The username and/or password is incorrect.';
   764       // Do we also need to increment the lockout countdown?
       
   765       if ( $policy != 'disable' && !defined('IN_ENANO_INSTALL') )
       
   766       {
       
   767         $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
       
   768         // increment fail count
       
   769         $this->sql('INSERT INTO '.table_prefix.'lockout(ipaddr, timestamp, action) VALUES(\'' . $ipaddr . '\', UNIX_TIMESTAMP(), \'credential\');');
       
   770         $fails++;
       
   771         return array(
       
   772             'success' => false,
       
   773             'error' => ( $fails >= $threshold ) ? 'locked_out' : 'invalid_credentials',
       
   774             'lockout_threshold' => $threshold,
       
   775             'lockout_duration' => ( $duration / 60 ),
       
   776             'lockout_fails' => $fails,
       
   777             'time_rem' => ( $duration / 60 ),
       
   778             'lockout_policy' => $policy
       
   779           );
       
   780       }
       
   781         
       
   782       return array(
       
   783         'success' => false,
       
   784         'error' => 'invalid_credentials'
       
   785       );
   678     }
   786     }
   679   }
   787   }
   680   
   788   
   681   /**
   789   /**
   682    * Attempts to login without using crypto stuff, mainly for use when the other side doesn't like Javascript
   790    * Attempts to login without using crypto stuff, mainly for use when the other side doesn't like Javascript
   698     if($this->compat)
   806     if($this->compat)
   699     {
   807     {
   700       return $this->login_compat($username, $pass_hashed, $level);
   808       return $this->login_compat($username, $pass_hashed, $level);
   701     }
   809     }
   702     
   810     
       
   811     if ( !defined('IN_ENANO_INSTALL') )
       
   812     {
       
   813       // Lockout stuff
       
   814       $threshold = ( $_ = getConfig('lockout_threshold') ) ? intval($_) : 5;
       
   815       $duration  = ( $_ = getConfig('lockout_duration') ) ? intval($_) : 15;
       
   816       // convert to minutes
       
   817       $duration  = $duration * 60;
       
   818       $policy = ( $x = getConfig('lockout_policy') && in_array(getConfig('lockout_policy'), array('lockout', 'disable', 'captcha')) ) ? getConfig('lockout_policy') : 'lockout';
       
   819       if ( $policy == 'captcha' && $captcha_hash && $captcha_code )
       
   820       {
       
   821         // policy is captcha -- check if it's correct, and if so, bypass lockout check
       
   822         $real_code = $this->get_captcha($captcha_hash);
       
   823       }
       
   824       if ( $policy != 'disable' && !( $policy == 'captcha' && isset($real_code) && $real_code == $captcha_code ) )
       
   825       {
       
   826         $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
       
   827         $timestamp_cutoff = time() - $duration;
       
   828         $q = $this->sql('SELECT timestamp FROM '.table_prefix.'lockout WHERE timestamp > ' . $timestamp_cutoff . ' AND ipaddr = \'' . $ipaddr . '\' ORDER BY timestamp DESC;');
       
   829         $fails = $db->numrows();
       
   830         if ( $fails > $threshold )
       
   831         {
       
   832           // ooh boy, somebody's in trouble ;-)
       
   833           $row = $db->fetchrow();
       
   834           $db->free_result();
       
   835           return array(
       
   836               'success' => false,
       
   837               'error' => 'locked_out',
       
   838               'lockout_threshold' => $threshold,
       
   839               'lockout_duration' => ( $duration / 60 ),
       
   840               'lockout_fails' => $fails,
       
   841               'lockout_policy' => $policy,
       
   842               'time_rem' => $duration - round( ( time() - $row['timestamp'] ) / 60 ),
       
   843               'lockout_last_time' => $row['timestamp']
       
   844             );
       
   845         }
       
   846         $db->free_result();
       
   847       }
       
   848     }
       
   849     
   703     // Instanciate the Rijndael encryption object
   850     // Instanciate the Rijndael encryption object
   704     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   851     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   705     
   852     
   706     // Initialize our success switch
   853     // Initialize our success switch
   707     $success = false;
   854     $success = false;
   708     
   855     
   709     // Retrieve the real password from the database
   856     // Retrieve the real password from the database
   710     $this->sql('SELECT password,old_encryption,user_id,user_level,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$this->prepare_text(strtolower($username)).'\';');
   857     $this->sql('SELECT password,old_encryption,user_id,user_level,temp_password,temp_password_time FROM '.table_prefix.'users WHERE lcase(username)=\''.$this->prepare_text(strtolower($username)).'\';');
   711     if($db->numrows() < 1)
   858     if($db->numrows() < 1)
   712       return 'The username and/or password is incorrect.';
   859     {
       
   860       // This wasn't logged in <1.0.2, dunno how it slipped through
       
   861       if($level > USER_LEVEL_MEMBER)
       
   862         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
       
   863       else
       
   864         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
       
   865       
       
   866       // Do we also need to increment the lockout countdown?
       
   867       if ( $policy != 'disable' && !defined('IN_ENANO_INSTALL') )
       
   868       {
       
   869         $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
       
   870         // increment fail count
       
   871         $this->sql('INSERT INTO '.table_prefix.'lockout(ipaddr, timestamp, action) VALUES(\'' . $ipaddr . '\', UNIX_TIMESTAMP(), \'credential\');');
       
   872         $fails++;
       
   873         return array(
       
   874             'success' => false,
       
   875             'error' => ( $fails >= $threshold ) ? 'locked_out' : 'invalid_credentials',
       
   876             'lockout_threshold' => $threshold,
       
   877             'lockout_duration' => ( $duration / 60 ),
       
   878             'lockout_fails' => $fails,
       
   879             'lockout_policy' => $policy
       
   880           );
       
   881       }
       
   882       
       
   883       return array(
       
   884         'success' => false,
       
   885         'error' => 'invalid_credentials'
       
   886       );
       
   887     }
   713     $row = $db->fetchrow();
   888     $row = $db->fetchrow();
   714     
   889     
   715     // Check to see if we're logging in using a temporary password
   890     // Check to see if we're logging in using a temporary password
   716     
   891     
   717     if((intval($row['temp_password_time']) + 3600*24) > time() )
   892     if((intval($row['temp_password_time']) + 3600*24) > time() )
   756       }
   931       }
   757     }
   932     }
   758     if($success)
   933     if($success)
   759     {
   934     {
   760       if((int)$level > (int)$row['user_level'])
   935       if((int)$level > (int)$row['user_level'])
   761         return 'You are not authorized for this level of access.';
   936         return array(
       
   937           'success' => false,
       
   938           'error' => 'too_big_for_britches'
       
   939         );
   762       $sess = $this->register_session(intval($row['user_id']), $username, $real_pass, $level);
   940       $sess = $this->register_session(intval($row['user_id']), $username, $real_pass, $level);
   763       if($sess)
   941       if($sess)
   764       {
   942       {
   765         if($level > USER_LEVEL_MEMBER)
   943         if($level > USER_LEVEL_MEMBER)
   766           $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
   944           $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_good\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
   771         foreach ( $code as $cmd )
   949         foreach ( $code as $cmd )
   772         {
   950         {
   773           eval($cmd);
   951           eval($cmd);
   774         }
   952         }
   775         
   953         
   776         return 'success';
   954         return array(
       
   955           'success' => true
       
   956           );
   777       }
   957       }
   778       else
   958       else
   779         return 'Your login credentials were correct, but an internal error occured while registering the session key in the database.';
   959         return array(
       
   960           'success' => false,
       
   961           'error' => 'backend_fail'
       
   962         );
   780     }
   963     }
   781     else
   964     else
   782     {
   965     {
   783       if($level > USER_LEVEL_MEMBER)
   966       if($level > USER_LEVEL_MEMBER)
   784         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
   967         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES(\'security\', \'admin_auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
   785       else
   968       else
   786         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
   969         $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
   787         
   970         
   788       return 'The username and/or password is incorrect.';
   971       // Do we also need to increment the lockout countdown?
       
   972       if ( $policy != 'disable' && !defined('IN_ENANO_INSTALL') )
       
   973       {
       
   974         $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
       
   975         // increment fail count
       
   976         $this->sql('INSERT INTO '.table_prefix.'lockout(ipaddr, timestamp, action) VALUES(\'' . $ipaddr . '\', UNIX_TIMESTAMP(), \'credential\');');
       
   977         $fails++;
       
   978         return array(
       
   979             'success' => false,
       
   980             'error' => ( $fails >= $threshold ) ? 'locked_out' : 'invalid_credentials',
       
   981             'lockout_threshold' => $threshold,
       
   982             'lockout_duration' => ( $duration / 60 ),
       
   983             'lockout_fails' => $fails,
       
   984             'lockout_policy' => $policy
       
   985           );
       
   986       }
       
   987         
       
   988       return array(
       
   989         'success' => false,
       
   990         'error' => 'invalid_credentials'
       
   991       );
   789     }
   992     }
   790   }
   993   }
   791   
   994   
   792   /**
   995   /**
   793    * Attempts to log in using the old table structure and algorithm.
   996    * Attempts to log in using the old table structure and algorithm.
   855     }
  1058     }
   856     else
  1059     else
   857     {
  1060     {
   858       // Stash it in a cookie
  1061       // Stash it in a cookie
   859       // For now, make the cookie last forever, we can change this in 1.1.x
  1062       // For now, make the cookie last forever, we can change this in 1.1.x
   860       setcookie( 'sid', $session_key, time()+315360000, scriptPath.'/' );
  1063       setcookie( 'sid', $session_key, time()+315360000, scriptPath.'/', null, ( isset($_SERVER['HTTPS']) ) );
   861       $_COOKIE['sid'] = $session_key;
  1064       $_COOKIE['sid'] = $session_key;
   862     }
  1065     }
   863     // $keyhash is stored in the database, this is for compatibility with the older DB structure
  1066     // $keyhash is stored in the database, this is for compatibility with the older DB structure
   864     $keyhash = md5($session_key);
  1067     $keyhash = md5($session_key);
   865     // Record the user's IP
  1068     // Record the user's IP
   917    */
  1120    */
   918    
  1121    
   919   function register_guest_session()
  1122   function register_guest_session()
   920   {
  1123   {
   921     global $db, $session, $paths, $template, $plugins; // Common objects
  1124     global $db, $session, $paths, $template, $plugins; // Common objects
       
  1125     global $lang;
   922     $this->username = $_SERVER['REMOTE_ADDR'];
  1126     $this->username = $_SERVER['REMOTE_ADDR'];
   923     $this->user_level = USER_LEVEL_GUEST;
  1127     $this->user_level = USER_LEVEL_GUEST;
   924     if($this->compat || defined('IN_ENANO_INSTALL'))
  1128     if($this->compat || defined('IN_ENANO_INSTALL'))
   925     {
  1129     {
   926       $this->theme = 'oxygen';
  1130       $this->theme = 'oxygen';
   930     {
  1134     {
   931       $this->theme = ( isset($_GET['theme']) && isset($template->named_theme_list[$_GET['theme']])) ? $_GET['theme'] : $template->default_theme;
  1135       $this->theme = ( isset($_GET['theme']) && isset($template->named_theme_list[$_GET['theme']])) ? $_GET['theme'] : $template->default_theme;
   932       $this->style = ( isset($_GET['style']) && file_exists(ENANO_ROOT.'/themes/'.$this->theme . '/css/'.$_GET['style'].'.css' )) ? $_GET['style'] : substr($template->named_theme_list[$this->theme]['default_style'], 0, strlen($template->named_theme_list[$this->theme]['default_style'])-4);
  1136       $this->style = ( isset($_GET['style']) && file_exists(ENANO_ROOT.'/themes/'.$this->theme . '/css/'.$_GET['style'].'.css' )) ? $_GET['style'] : substr($template->named_theme_list[$this->theme]['default_style'], 0, strlen($template->named_theme_list[$this->theme]['default_style'])-4);
   933     }
  1137     }
   934     $this->user_id = 1;
  1138     $this->user_id = 1;
       
  1139     if ( !defined('ENANO_ALLOW_LOAD_NOLANG') )
       
  1140     {
       
  1141       // This is a VERY special case we are allowing. It lets the installer create languages using the Enano API.
       
  1142       $language = intval(getConfig('default_language'));
       
  1143       $lang = new Language($language);
       
  1144     }
   935   }
  1145   }
   936   
  1146   
   937   /**
  1147   /**
   938    * Validates a session key, and returns the userdata associated with the key or false
  1148    * Validates a session key, and returns the userdata associated with the key or false
   939    * @param string $key The session key to validate
  1149    * @param string $key The session key to validate
   957       // echo '(debug) $session->validate_session: Key does not match regex<br />Decrypted key: '.$decrypted_key;
  1167       // echo '(debug) $session->validate_session: Key does not match regex<br />Decrypted key: '.$decrypted_key;
   958       return false;
  1168       return false;
   959     }
  1169     }
   960     $keyhash = md5($key);
  1170     $keyhash = md5($key);
   961     $salt = $db->escape($keydata[3]);
  1171     $salt = $db->escape($keydata[3]);
   962     $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,x.* FROM '.table_prefix.'session_keys AS k
  1172     $query = $db->sql_query('SELECT u.user_id AS uid,u.username,u.password,u.email,u.real_name,u.user_level,u.theme,u.style,u.signature,u.reg_time,u.account_active,u.activation_key,k.source_ip,k.time,k.auth_level,COUNT(p.message_id) AS num_pms,u.user_lang,x.* FROM '.table_prefix.'session_keys AS k
   963                                LEFT JOIN '.table_prefix.'users AS u
  1173                                LEFT JOIN '.table_prefix.'users AS u
   964                                  ON ( u.user_id=k.user_id )
  1174                                  ON ( u.user_id=k.user_id )
   965                                LEFT JOIN '.table_prefix.'users_extra AS x
  1175                                LEFT JOIN '.table_prefix.'users_extra AS x
   966                                  ON ( u.user_id=x.user_id OR x.user_id IS NULL )
  1176                                  ON ( u.user_id=x.user_id OR x.user_id IS NULL )
   967                                LEFT JOIN '.table_prefix.'privmsgs AS p
  1177                                LEFT JOIN '.table_prefix.'privmsgs AS p
  1112     $ou = $this->username;
  1322     $ou = $this->username;
  1113     $oid = $this->user_id;
  1323     $oid = $this->user_id;
  1114     if($level > USER_LEVEL_CHPREF)
  1324     if($level > USER_LEVEL_CHPREF)
  1115     {
  1325     {
  1116       $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  1326       $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  1117       if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD) return 'success';
  1327       if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD)
       
  1328       {
       
  1329         return 'success';
       
  1330       }
  1118       // Destroy elevated privileges
  1331       // Destroy elevated privileges
  1119       $keyhash = md5(strrev($this->sid_super));
  1332       $keyhash = md5(strrev($this->sid_super));
  1120       $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.$keyhash.'\' AND user_id=\'' . $this->user_id . '\';');
  1333       $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.$keyhash.'\' AND user_id=\'' . $this->user_id . '\';');
  1121       $this->sid_super = false;
  1334       $this->sid_super = false;
  1122       $this->auth_level = USER_LEVEL_MEMBER;
  1335       $this->auth_level = USER_LEVEL_MEMBER;
  2115     {
  2328     {
  2116       // Permissions table not yet initialized
  2329       // Permissions table not yet initialized
  2117       return false;
  2330       return false;
  2118     }
  2331     }
  2119     
  2332     
       
  2333     // cache of permission objects (to save RAM and SQL queries)
       
  2334     static $objcache = array();
       
  2335     
       
  2336     if ( count($objcache) == 0 )
       
  2337     {
       
  2338       foreach ( $paths->nslist as $key => $_ )
       
  2339       {
       
  2340         $objcache[$key] = array();
       
  2341       }
       
  2342     }
       
  2343     
       
  2344     if ( isset($objcache[$namespace][$page_id]) )
       
  2345     {
       
  2346       return $objcache[$namespace][$page_id];
       
  2347     }
       
  2348     
  2120     //if ( !isset( $paths->pages[$paths->nslist[$namespace] . $page_id] ) )
  2349     //if ( !isset( $paths->pages[$paths->nslist[$namespace] . $page_id] ) )
  2121     //{
  2350     //{
  2122     //  // Page does not exist
  2351     //  // Page does not exist
  2123     //  return false;
  2352     //  return false;
  2124     //}
  2353     //}
  2125     
  2354     
  2126     $object = new Session_ACLPageInfo( $page_id, $namespace, $this->acl_types, $this->acl_descs, $this->acl_deps, $this->acl_base_cache );
  2355     $objcache[$namespace][$page_id] = new Session_ACLPageInfo( $page_id, $namespace, $this->acl_types, $this->acl_descs, $this->acl_deps, $this->acl_base_cache );
       
  2356     $object =& $objcache[$namespace][$page_id];
  2127     
  2357     
  2128     return $object;
  2358     return $object;
  2129     
  2359     
  2130   }
  2360   }
  2131   
  2361