includes/sessions.php
changeset 1103 90225c988124
parent 1101 30d8bb88572d
child 1132 05fe0039d952
--- a/includes/sessions.php	Tue Aug 25 01:43:11 2009 -0400
+++ b/includes/sessions.php	Tue Aug 25 01:43:40 2009 -0400
@@ -2,8 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.6 (Caoineag beta 1)
- * Copyright (C) 2006-2008 Dan Fuhry
+ * Copyright (C) 2006-2009 Dan Fuhry
  * sessions.php - everything related to security and user management
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -158,6 +157,20 @@
   var $auth_level = 1;
   
   /**
+   * Preference for date formatting
+   * @var string
+   */
+  
+  var $date_format = DATE_4;
+  
+  /**
+   * Preference for time formatting
+   * @var string
+   */
+  
+  var $time_format = TIME_24_NS;
+  
+  /**
    * State variable to track if a session timed out
    * @var bool
    */
@@ -413,6 +426,28 @@
     return $result;
   }
   
+  /**
+   * Returns true if we're currently on a page that shouldn't be blocked even if we have an inactive or banned account
+   * @param bool strict - if true, whitelist of pages is even stricter (Login, Logout and CSS only). if false (default), admin access is allowed, assuming other factors allow it
+   * @return bool
+   */
+  
+  function on_critical_page($strict = false)
+  {
+    global $title;
+    list($page_id, $namespace) = RenderMan::strToPageID($title);
+    list($page_id) = explode('/', $page_id);
+    
+    if ( $strict )
+    {
+      return $namespace == 'Special' && in_array($page_id, array('CSS', 'Login', 'Logout'));
+    }
+    else
+    {
+      return $namespace == 'Admin' || ($namespace == 'Special' && in_array($page_id, array('CSS', 'Login', 'Logout', 'Administration')));
+    }
+  }
+  
   # Session restoration and permissions
   
   /**
@@ -439,13 +474,6 @@
       }
       if ( is_array($userdata) )
       {
-        $data = RenderMan::strToPageID($paths->get_pageid_from_url());
-        
-        if(!$this->compat && $userdata['account_active'] != 1 && $data[1] != 'Special' && $data[1] != 'Admin')
-        {
-          $this->show_inactive_error($userdata);
-        }
-        
         $this->sid = $_COOKIE['sid'];
         $this->user_logged_in = true;
         $this->user_id =       intval($userdata['user_id']);
@@ -553,6 +581,12 @@
     // make sure we aren't banned
     $this->check_banlist();
     
+    // make sure the account is active
+    if ( !$this->compat && $this->user_logged_in && $userdata['account_active'] != 1 && !$this->on_critical_page() )
+    {
+      $this->show_inactive_error($userdata);
+    }
+    
     // Printable page view? Probably the wrong place to control
     // it but $template is pretty dumb, it will just about always
     // do what you ask it to do, which isn't always what we want
@@ -724,11 +758,11 @@
       // This wasn't logged in <1.0.2, dunno how it slipped through
       if ( $level > USER_LEVEL_MEMBER )
         $this->sql('INSERT INTO ' . table_prefix . "logs(log_type,action,time_id,date_string,author,edit_summary,page_text) VALUES\n"
-                   . '  (\'security\', \'admin_auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', '
+                   . '  (\'security\', \'admin_auth_bad\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', '
                       . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
       else
         $this->sql('INSERT INTO ' . table_prefix . "logs(log_type,action,time_id,date_string,author,edit_summary) VALUES\n"
-                   . '  (\'security\', \'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', '
+                   . '  (\'security\', \'auth_bad\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', '
                       . '\''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
       
       // Do we also need to increment the lockout countdown?
@@ -822,13 +856,16 @@
           'success' => false,
           'error' => 'too_big_for_britches'
         );
+      
+      // grant session
       $sess = $this->register_session($row['user_id'], $username, ( isset($password_hmac) ? $password_hmac : $password ), $level, $remember);
+      
       if($sess)
       {
         if($level > USER_LEVEL_MEMBER)
-          $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().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+          $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().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
         else
-          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+          $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_good\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
         
         $code = $plugins->setHook('login_success');
         foreach ( $code as $cmd )
@@ -849,9 +886,9 @@
     else
     {
       if($level > USER_LEVEL_MEMBER)
-        $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().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
+        $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().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\', ' . intval($level) . ')');
       else
-        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
+        $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'auth_bad\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($username).'\', \''.$db->escape($_SERVER['REMOTE_ADDR']).'\')');
         
       // Do we also need to increment the lockout countdown?
       if ( !defined('IN_ENANO_INSTALL') && $lockout_data['lockout_policy'] != 'disable' )
@@ -967,6 +1004,7 @@
       // For now, make the cookie last forever, we can change this in 1.1.x
       setcookie( 'sid', $session_key, time()+15552000, scriptPath.'/', null, $GLOBALS['is_https']);
       $_COOKIE['sid'] = $session_key;
+      $this->sid = $session_key;
     }
     // $keyhash is stored in the database, this is for compatibility with the older DB structure
     $keyhash = md5($session_key);
@@ -1192,7 +1230,7 @@
                       . "           u.reg_time, u.account_active, u.activation_key, u.user_lang, u.user_timezone, u.user_title, u.user_dst,\n"
                       . "           k.salt, k.source_ip, k.time, k.auth_level, k.key_type, x.user_id, x.user_aim, x.user_yahoo, x.user_msn,\n"
                       . "           x.user_xmpp, x.user_homepage, x.user_location, x.user_job, x.user_hobbies, x.email_public,\n"
-                      . "           x.disable_js_fx";
+                      . "           x.disable_js_fx, x.date_format, x.time_format";
     
     $joins = "  LEFT JOIN " . table_prefix . "users AS u\n"
             . "    ON ( u.user_id=k.user_id )\n"
@@ -1221,14 +1259,14 @@
     
     if ( !$query && ( defined('IN_ENANO_INSTALL') or defined('IN_ENANO_UPGRADE') ) )
     {
-      $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,\'\' AS password_salt,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, 1440 AS user_timezone, \'0;0;0;0;60\' AS user_dst, ' . SK_SHORT . ' AS key_type FROM '.table_prefix.'session_keys AS k
+      $key_md5 = $loose_call ? $key : md5($key);
+      $query = $this->sql('SELECT u.user_id AS uid,u.username,u.password,\'\' AS password_salt,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, 1440 AS user_timezone, \'0;0;0;0;60\' AS user_dst, ' . SK_SHORT . ' AS key_type, k.salt FROM '.table_prefix.'session_keys AS k
                              LEFT JOIN '.table_prefix.'users AS u
                                ON ( u.user_id=k.user_id )
                              LEFT JOIN '.table_prefix.'privmsgs AS p
                                ON ( p.message_to=u.username AND p.message_read=0 )
-                             WHERE k.session_key=\''.$key.'\'
-                               AND k.salt=\''.$salt.'\'
-                             GROUP BY u.user_id,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;');
+                             WHERE k.session_key=\''.$key_md5.'\'
+                             GROUP BY u.user_id,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,k.salt;');
     }
     else if ( !$query )
     {
@@ -1236,7 +1274,7 @@
     }
     if($db->numrows() < 1)
     {
-      // echo '(debug) $session->validate_session: Key was not found in database<br />';
+      // echo '(debug) $session->validate_session: Key was not found in database: ' . $key_md5 . '<br />';
       return false;
     }
     $row = $db->fetchrow();
@@ -1346,6 +1384,11 @@
         $user_extra[$column] = '';
     }
     
+    if ( isset($row['date_format']) )
+      $this->date_format = $row['date_format'];
+    if ( isset($row['time_format']) )
+      $this->time_format = $row['time_format'];
+    
     $this->user_extra = $user_extra;
     // Leave the rest to PHP's automatic garbage collector ;-)
     
@@ -1476,6 +1519,9 @@
     global $db, $session, $paths, $template, $plugins; // Common objects
     global $lang;
     
+    global $title;
+    $paths->init($title);
+    
     $language = intval(getConfig('default_language'));
     $lang = new Language($language);
     @setlocale(LC_ALL, $lang->lang_code);
@@ -1541,7 +1587,10 @@
       }
     }
     
-    die_semicritical($lang->get('user_login_noact_title'), '<p>' . $lang->get('user_login_noact_msg_intro') . ' '.$solution.'</p>' . $form);
+    global $output;
+    $output = new Output_HTML();
+    $output->set_title($lang->get('user_login_noact_title'));
+    die_friendly($lang->get('user_login_noact_title'), '<p>' . $lang->get('user_login_noact_msg_intro') . ' '.$solution.'</p>' . $form);
   }
   
   /**
@@ -1757,7 +1806,9 @@
     global $db, $session, $paths, $template, $plugins; // Common objects
     global $lang;
     
-    $col_reason = ( $this->compat ) ? '"No reason entered (session manager is in compatibility mode)" AS reason' : 'reason';
+    $col_reason = ( $this->compat ) ? '\'No reason available (session manager is in compatibility mode)\' AS reason' : 'reason';
+    $remote_addr = ( strstr($_SERVER['REMOTE_ADDR'], ':') ) ? expand_ipv6_address($_SERVER['REMOTE_ADDR']) : $_SERVER['REMOTE_ADDR'];
+    
     $banned = false;
     if ( $this->user_logged_in )
     {
@@ -1797,7 +1848,7 @@
             {
               continue;
             }
-            if ( preg_match("/$regexp/", $_SERVER['REMOTE_ADDR']) )
+            if ( preg_match("/$regexp/", $remote_addr) )
             {
               $reason = $reason_temp;
               $banned = true;
@@ -1840,8 +1891,11 @@
             // check range
             $regexp = parse_ip_range_regex($ban_value);
             if ( !$regexp )
+            {
+              die("bad regexp for $ban_value");
               continue;
-            if ( preg_match("/$regexp/", $_SERVER['REMOTE_ADDR']) )
+            }
+            if ( preg_match("/$regexp/", $remote_addr) )
             {
               $reason = $reason_temp;
               $banned = true;
@@ -1857,7 +1911,7 @@
       }
       $db->free_result();
     }
-    if ( $banned && $paths->get_pageid_from_url() != $paths->nslist['Special'].'CSS' )
+    if ( $banned && !$this->on_critical_page(true) )
     {
       // This guy is banned - kill the session, kill the database connection, bail out, and be pretty about it
       die_semicritical($lang->get('user_ban_msg_title'), '<p>' . $lang->get('user_ban_msg_body') . '</p><div class="error-box"><b>' . $lang->get('user_ban_lbl_reason') . '</b><br />' . $reason . '</div>');
@@ -2229,7 +2283,7 @@
   function admin_activation_request($u)
   {
     global $db;
-    $this->sql('INSERT INTO '.table_prefix.'logs(log_type, action, time_id, date_string, author, edit_summary) VALUES(\'admin\', \'activ_req\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$this->username.'\', \''.$db->escape($u).'\');');
+    $this->sql('INSERT INTO '.table_prefix.'logs(log_type, action, time_id, date_string, author, edit_summary) VALUES(\'admin\', \'activ_req\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$this->username.'\', \''.$db->escape($u).'\');');
   }
   
   /**
@@ -2245,11 +2299,11 @@
     $r = mysql_affected_rows();
     if ( $r > 0 )
     {
-      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_good\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
+      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_good\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
     }
     else
     {
-      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_bad\', '.time().', \''.enano_date('d M Y h:i a').'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
+      $e = $this->sql('INSERT INTO '.table_prefix.'logs(log_type,action,time_id,date_string,author,edit_summary) VALUES(\'security\', \'activ_bad\', '.time().', \''.enano_date(ED_DATE | ED_TIME).'\', \''.$db->escape($user).'\', \''.$_SERVER['REMOTE_ADDR'].'\')');
     }
     return $r;
   }