includes/sessions.php
changeset 271 f088805540ae
parent 266 917dcc6c4ceb
parent 270 5bcdee999015
child 304 e2cb5f1432c8
equal deleted inserted replaced
266:917dcc6c4ceb 271:f088805540ae
   149    * Regex that defines a valid username, minus the ^ and $, these are added later
   149    * Regex that defines a valid username, minus the ^ and $, these are added later
   150    * @var string
   150    * @var string
   151    */
   151    */
   152    
   152    
   153   //var $valid_username = '([A-Za-z0-9 \!\@\(\)-]+)';
   153   //var $valid_username = '([A-Za-z0-9 \!\@\(\)-]+)';
   154   var $valid_username = '([^<>_&\?\'"%\n\r\t\a\/]+)';
   154   var $valid_username = '([^<>&\?\'"%\n\r\t\a\/]+)';
   155    
   155    
   156   /**
   156   /**
   157    * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
   157    * What we're allowed to do as far as permissions go. This changes based on the value of the "auth" URI param.
   158    * @var string
   158    * @var string
   159    */
   159    */
   258    */
   258    */
   259    
   259    
   260   function __construct()
   260   function __construct()
   261   {
   261   {
   262     global $db, $session, $paths, $template, $plugins; // Common objects
   262     global $db, $session, $paths, $template, $plugins; // Common objects
   263     include(ENANO_ROOT.'/config.php');
   263     
       
   264     if ( defined('IN_ENANO_INSTALL') )
       
   265     {
       
   266       @include(ENANO_ROOT.'/config.new.php');
       
   267     }
       
   268     else
       
   269     {
       
   270       @include(ENANO_ROOT.'/config.php');
       
   271     }
       
   272     
   264     unset($dbhost, $dbname, $dbuser, $dbpasswd);
   273     unset($dbhost, $dbname, $dbuser, $dbpasswd);
   265     if(isset($crypto_key))
   274     if(isset($crypto_key))
   266     {
   275     {
   267       $this->private_key = $crypto_key;
   276       $this->private_key = $crypto_key;
   268       $this->private_key = hexdecode($this->private_key);
   277       $this->private_key = hexdecode($this->private_key);
   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.
   570    * @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.
   571    * @param array $captcha_code Optional. If we're locked out and the lockout policy is captcha, this should be the code the user entered.
   563    * @return string 'success' on success, or error string on failure
   572    * @return string 'success' on success, or error string on failure
   564    */
   573    */
   565    
   574    
   566   function login_with_crypto($username, $aes_data, $aes_key, $challenge, $level = USER_LEVEL_MEMBER, $captcha_hash = false, $captcha_code = false)
   575   function login_with_crypto($username, $aes_data, $aes_key_id, $challenge, $level = USER_LEVEL_MEMBER, $captcha_hash = false, $captcha_code = false)
   567   {
   576   {
   568     global $db, $session, $paths, $template, $plugins; // Common objects
   577     global $db, $session, $paths, $template, $plugins; // Common objects
   569     
   578     
   570     $privcache = $this->private_key;
   579     $privcache = $this->private_key;
   571 
   580 
   611     // Instanciate the Rijndael encryption object
   620     // Instanciate the Rijndael encryption object
   612     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   621     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
   613     
   622     
   614     // Fetch our decryption key
   623     // Fetch our decryption key
   615     
   624     
   616     $aes_key = $this->fetch_public_key($aes_key);
   625     $aes_key = $this->fetch_public_key($aes_key_id);
   617     if(!$aes_key)
   626     if(!$aes_key)
   618       return array(
   627       return array(
   619         'success' => false,
   628         'success' => false,
   620         'error' => 'key_not_found'
   629         'error' => 'key_not_found'
   621         );
   630         );
   634     
   643     
   635     // Initialize our success switch
   644     // Initialize our success switch
   636     $success = false;
   645     $success = false;
   637     
   646     
   638     // Escaped username
   647     // Escaped username
       
   648     $username = str_replace('_', ' ', $username);
   639     $db_username_lower = $this->prepare_text(strtolower($username));
   649     $db_username_lower = $this->prepare_text(strtolower($username));
   640     $db_username       = $this->prepare_text($username);
   650     $db_username       = $this->prepare_text($username);
   641     
   651     
   642     // Select the user data from the table, and decrypt that so we can verify the password
   652     // Select the user data from the table, and decrypt that so we can verify the password
   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 . '\';');
   653     $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 . '\';');
   799   function login_without_crypto($username, $password, $already_md5ed = false, $level = USER_LEVEL_MEMBER)
   809   function login_without_crypto($username, $password, $already_md5ed = false, $level = USER_LEVEL_MEMBER)
   800   {
   810   {
   801     global $db, $session, $paths, $template, $plugins; // Common objects
   811     global $db, $session, $paths, $template, $plugins; // Common objects
   802     
   812     
   803     $pass_hashed = ( $already_md5ed ) ? $password : md5($password);
   813     $pass_hashed = ( $already_md5ed ) ? $password : md5($password);
       
   814     
       
   815     // Replace underscores with spaces in username
       
   816     // (Added in 1.0.2)
       
   817     $username = str_replace('_', ' ', $username);
   804     
   818     
   805     // Perhaps we're upgrading Enano?
   819     // Perhaps we're upgrading Enano?
   806     if($this->compat)
   820     if($this->compat)
   807     {
   821     {
   808       return $this->login_compat($username, $pass_hashed, $level);
   822       return $this->login_compat($username, $pass_hashed, $level);
  1023     }
  1037     }
  1024   }
  1038   }
  1025   
  1039   
  1026   /**
  1040   /**
  1027    * Registers a session key in the database. This function *ASSUMES* that the username and password have already been validated!
  1041    * Registers a session key in the database. This function *ASSUMES* that the username and password have already been validated!
  1028    * Basically the session key is a base64-encoded cookie (encrypted with the site's private key) that says "u=[username];p=[sha1 of password]"
  1042    * Basically the session key is a hex-encoded cookie (encrypted with the site's private key) that says "u=[username];p=[sha1 of password];s=[unique key id]"
  1029    * @param int $user_id
  1043    * @param int $user_id
  1030    * @param string $username
  1044    * @param string $username
  1031    * @param string $password
  1045    * @param string $password
  1032    * @param int $level The level of access to grant, defaults to USER_LEVEL_MEMBER
  1046    * @param int $level The level of access to grant, defaults to USER_LEVEL_MEMBER
  1033    * @return bool
  1047    * @return bool
  1082     $query = $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key, salt, user_id, auth_level, source_ip, time) VALUES(\''.$keyhash.'\', \''.$salt.'\', '.$user_id.', '.$level.', \''.$ip.'\', '.$time.');');
  1096     $query = $this->sql('INSERT INTO '.table_prefix.'session_keys(session_key, salt, user_id, auth_level, source_ip, time) VALUES(\''.$keyhash.'\', \''.$salt.'\', '.$user_id.', '.$level.', \''.$ip.'\', '.$time.');');
  1083     return true;
  1097     return true;
  1084   }
  1098   }
  1085   
  1099   
  1086   /**
  1100   /**
  1087    * Identical to register_session in nature, but uses the old login/table structure. DO NOT use this.
  1101    * Identical to register_session in nature, but uses the old login/table structure. DO NOT use this except in the upgrade script under very controlled circumstances.
  1088    * @see sessionManager::register_session()
  1102    * @see sessionManager::register_session()
  1089    * @access private
  1103    * @access private
  1090    */
  1104    */
  1091   
  1105   
  1092   function register_session_compat($user_id, $username, $password, $level = 0)
  1106   function register_session_compat($user_id, $username, $password, $level = 0)
  1534    */
  1548    */
  1535    
  1549    
  1536   function check_banlist()
  1550   function check_banlist()
  1537   {
  1551   {
  1538     global $db, $session, $paths, $template, $plugins; // Common objects
  1552     global $db, $session, $paths, $template, $plugins; // Common objects
  1539     if($this->compat)
  1553     $col_reason = ( $this->compat ) ? '"No reason entered (session manager is in compatibility mode)" AS reason' : 'reason';
  1540       $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex FROM '.table_prefix.'banlist ORDER BY ban_type;');
  1554     $is_banned = false;
  1541     else
  1555     if ( $this->user_logged_in )
  1542       $q = $this->sql('SELECT ban_id,ban_type,ban_value,is_regex,reason FROM '.table_prefix.'banlist ORDER BY ban_type;');
  1556     {
  1543     if(!$q) $db->_die('The banlist data could not be selected.');
  1557       // check by IP, email, and username
  1544     $banned = false;
  1558       $sql = "SELECT $col_reason, ban_value, ban_type, is_regex FROM " . table_prefix . "banlist WHERE \n"
  1545     while($row = $db->fetchrow())
  1559             . "    ( ban_type = " . BAN_IP    . " AND is_regex = 0 ) OR \n"
  1546     {
  1560             . "    ( ban_type = " . BAN_IP    . " AND is_regex = 1 AND '{$_SERVER['REMOTE_ADDR']}' REGEXP ban_value ) OR \n"
  1547       if($this->compat)
  1561             . "    ( ban_type = " . BAN_USER  . " AND is_regex = 0 AND ban_value = '{$this->username}' ) OR \n"
  1548         $row['reason'] = 'None available - session manager is in compatibility mode';
  1562             . "    ( ban_type = " . BAN_USER  . " AND is_regex = 1 AND '{$this->username}' REGEXP ban_value ) OR \n"
  1549       switch($row['ban_type'])
  1563             . "    ( ban_type = " . BAN_EMAIL . " AND is_regex = 0 AND ban_value = '{$this->email}' ) OR \n"
  1550       {
  1564             . "    ( ban_type = " . BAN_EMAIL . " AND is_regex = 1 AND '{$this->email}' REGEXP ban_value ) \n"
  1551       case BAN_IP:
  1565             . "  ORDER BY ban_type ASC;";
  1552         if(intval($row['is_regex'])==1) {
  1566       $q = $this->sql($sql);
  1553           if(preg_match('#'.$row['ban_value'].'#i', $_SERVER['REMOTE_ADDR']))
  1567       if ( $db->numrows() > 0 )
       
  1568       {
       
  1569         while ( list($reason, $ban_value, $ban_type, $is_regex) = $db->fetchrow_num() )
       
  1570         {
       
  1571           if ( $ban_type == BAN_IP && $row['is_regex'] != 1 )
  1554           {
  1572           {
       
  1573             // check range
       
  1574             $regexp = parse_ip_range_regex($ban_value);
       
  1575             if ( !$regexp )
       
  1576             {
       
  1577               continue;
       
  1578             }
       
  1579             if ( preg_match("/$regexp/", $_SERVER['REMOTE_ADDR']) )
       
  1580             {
       
  1581               $banned = true;
       
  1582             }
       
  1583           }
       
  1584           else
       
  1585           {
       
  1586             // User is banned
  1555             $banned = true;
  1587             $banned = true;
  1556             $reason = $row['reason'];
       
  1557           }
  1588           }
  1558         }
  1589         }
  1559         else {
  1590       }
  1560           if($row['ban_value']==$_SERVER['REMOTE_ADDR']) { $banned = true; $reason = $row['reason']; }
  1591       $db->free_result();
  1561         }
  1592     }
  1562         break;
  1593     else
  1563       case BAN_USER:
  1594     {
  1564         if(intval($row['is_regex'])==1) {
  1595       // check by IP only
  1565           if(preg_match('#'.$row['ban_value'].'#i', $this->username))
  1596       $sql = "SELECT $col_reason, ban_value, ban_type, is_regex FROM " . table_prefix . "banlist WHERE
       
  1597                 ( ban_type = " . BAN_IP    . " AND is_regex = 0 ) OR
       
  1598                 ( ban_type = " . BAN_IP    . " AND is_regex = 1 AND '{$_SERVER['REMOTE_ADDR']}' REGEXP ban_value )
       
  1599               ORDER BY ban_type ASC;";
       
  1600       $q = $this->sql($sql);
       
  1601       if ( $db->numrows() > 0 )
       
  1602       {
       
  1603         while ( list($reason, $ban_value, $ban_type, $is_regex) = $db->fetchrow_num() )
       
  1604         {
       
  1605           if ( $ban_type == BAN_IP && $row['is_regex'] != 1 )
  1566           {
  1606           {
       
  1607             // check range
       
  1608             $regexp = parse_ip_range_regex($ban_value);
       
  1609             if ( !$regexp )
       
  1610               continue;
       
  1611             if ( preg_match("/$regexp/", $_SERVER['REMOTE_ADDR']) )
       
  1612             {
       
  1613               $banned = true;
       
  1614             }
       
  1615           }
       
  1616           else
       
  1617           {
       
  1618             // User is banned
  1567             $banned = true;
  1619             $banned = true;
  1568             $reason = $row['reason'];
       
  1569           }
  1620           }
  1570         }
  1621         }
  1571         else {
  1622       }
  1572           if($row['ban_value']==$this->username) { $banned = true; $reason = $row['reason']; }
  1623       $db->free_result();
  1573         }
  1624     }
  1574         break;
  1625     if ( $banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS' )
  1575       case BAN_EMAIL:
       
  1576         if(intval($row['is_regex'])==1) {
       
  1577           if(preg_match('#'.$row['ban_value'].'#i', $this->email))
       
  1578           {
       
  1579             $banned = true;
       
  1580             $reason = $row['reason'];
       
  1581           }
       
  1582         }
       
  1583         else {
       
  1584           if($row['ban_value']==$this->email) { $banned = true; $reason = $row['reason']; }
       
  1585         }
       
  1586         break;
       
  1587       default:
       
  1588         die('Ban error: rule "'.$row['ban_value'].'" has an invalid type ('.$row['ban_type'].')');
       
  1589       }
       
  1590     }
       
  1591     if($banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS')
       
  1592     {
  1626     {
  1593       // This guy is banned - kill the session, kill the database connection, bail out, and be pretty about it
  1627       // This guy is banned - kill the session, kill the database connection, bail out, and be pretty about it
  1594       die_semicritical('Ban notice', '<div class="error-box">You have been banned from this website. Please contact the site administrator for more information.<br /><br />Reason:<br />'.$reason.'</div>');
  1628       die_semicritical('Ban notice', '<div class="error-box">You have been banned from this website. Please contact the site administrator for more information.<br /><br />Reason:<br />'.$reason.'</div>');
  1595       exit;
  1629       exit;
  1596     }
  1630     }
  1598   
  1632   
  1599   # Registration
  1633   # Registration
  1600   
  1634   
  1601   /**
  1635   /**
  1602    * Registers a user. This does not perform any type of login.
  1636    * Registers a user. This does not perform any type of login.
  1603    * @param string $username
  1637    * @param string New user's username
  1604    * @param string $password This should be unencrypted.
  1638    * @param string This should be unencrypted.
  1605    * @param string $email
  1639    * @param string E-mail address.
  1606    * @param string $real_name Optional, defaults to ''.
  1640    * @param string Optional, defaults to ''.
  1607    * @param bool   $coppa     Optional. If true, the account is not activated initially and an admin activation request is sent. The caller is responsible for sending the address info and notice.
  1641    * @param bool Optional. If true, the account is not activated initially and an admin activation request is sent. The caller is responsible for sending the address info and notice.
  1608    */
  1642    */
  1609    
  1643    
  1610   function create_user($username, $password, $email, $real_name = '', $coppa = false)
  1644   function create_user($username, $password, $email, $real_name = '', $coppa = false)
  1611   {
  1645   {
  1612     global $db, $session, $paths, $template, $plugins; // Common objects
  1646     global $db, $session, $paths, $template, $plugins; // Common objects
  1613     
  1647     
  1614     // Initialize AES
  1648     // Initialize AES
  1615     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  1649     $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE);
  1616     
  1650     
  1617     if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.';
  1651     if(!preg_match('#^'.$this->valid_username.'$#', $username)) return 'The username you chose contains invalid characters.';
       
  1652     $username = str_replace('_', ' ', $username);
  1618     $user_orig = $username;
  1653     $user_orig = $username;
  1619     $username = $this->prepare_text($username);
  1654     $username = $this->prepare_text($username);
  1620     $email = $this->prepare_text($email);
  1655     $email = $this->prepare_text($email);
  1621     $real_name = $this->prepare_text($real_name);
  1656     $real_name = $this->prepare_text($real_name);
  1622     
  1657