From aad6e2a9c4857715c8bd56693d21b87dd0c16263 Mon Sep 17 00:00:00 2001
From: thomascube <thomas@roundcube.net>
Date: Tue, 27 Mar 2007 05:34:30 -0400
Subject: [PATCH] New session authentication, should fix bugs #1483951 and #1484299; testing required

---
 CHANGELOG                   |    6 +++
 index.php                   |   16 +++++--
 program/include/session.inc |   37 ++++++++++++++++++
 program/include/main.inc    |   43 +++++++++++++--------
 UPGRADING                   |    1 
 config/main.inc.php.dist    |    6 ++
 6 files changed, 86 insertions(+), 23 deletions(-)

diff --git a/CHANGELOG b/CHANGELOG
index ab5980e..f02a1ad 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,6 +1,12 @@
 CHANGELOG RoundCube Webmail
 ---------------------------
 
+2007/03/27 (thomasb)
+----------
+- New session authentication: Change sessid cookie when login, authentication with sessauth cookie is now configurable.
+  Should close bugs #1483951 and #1484299
+
+
 2007/03/23 (thomasb)
 ----------
 - Correctly translate mailbox names (closes #1484276)
diff --git a/UPGRADING b/UPGRADING
index 4b4d0d8..4fc2576 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -16,6 +16,7 @@
   $rcmail_config['htmleditor'] = TRUE;
   $rcmail_config['preview_pane'] = TRUE;
   $rcmail_config['date_today'] = 'H:i';
+  $rcmail_config['double_auth'] = TRUE;
 
 
 form version 0.1-beta
diff --git a/config/main.inc.php.dist b/config/main.inc.php.dist
index 490c623..c2c9d39 100644
--- a/config/main.inc.php.dist
+++ b/config/main.inc.php.dist
@@ -97,7 +97,11 @@
 $rcmail_config['session_lifetime'] = 10;
 
 // check client IP in session athorization
-$rcmail_config['ip_check'] = TRUE;
+$rcmail_config['ip_check'] = false;
+
+// Use an additional frequently changing cookie to athenticate user sessions.
+// There have been problems reported with this feature.
+$rcmail_config['double_auth'] = false;
 
 // this key is used to encrypt the users imap password which is stored
 // in the session record (and the client cookie if remember password is enabled).
diff --git a/index.php b/index.php
index eaecfdf..f365ef9 100644
--- a/index.php
+++ b/index.php
@@ -2,7 +2,7 @@
 /*
  +-----------------------------------------------------------------------+
  | RoundCube Webmail IMAP Client                                         |
- | Version 0.1-20070301                                                  |
+ | Version 0.1-20070327                                                  |
  |                                                                       |
  | Copyright (C) 2005-2007, RoundCube Dev. - Switzerland                 |
  | Licensed under the GNU GPL                                            |
@@ -40,7 +40,7 @@
 
 */
 
-define('RCMAIL_VERSION', '0.1-20070301');
+define('RCMAIL_VERSION', '0.1-20070327');
 
 // define global vars
 $CHARSET = 'UTF-8';
@@ -172,10 +172,17 @@
     {
     show_message("cookiesdisabled", 'warning');
     }
-  else if (isset($_POST['_user']) && isset($_POST['_pass']) &&
+  else if ($_SESSION['temp'] && isset($_POST['_user']) && isset($_POST['_pass']) &&
            rcmail_login(get_input_value('_user', RCUBE_INPUT_POST),
               get_input_value('_pass', RCUBE_INPUT_POST, true, 'ISO-8859-1'), $host))
     {
+    // create new session ID
+    unset($_SESSION['temp']);
+    sess_regenerate_id();
+
+    // send auth cookie if necessary
+    rcmail_authenticate_session();
+
     // send redirect
     header("Location: $COMM_PATH");
     exit;
@@ -197,8 +204,7 @@
 // check session and auth cookie
 else if ($_action != 'login' && $_SESSION['user_id'] && $_action != 'send')
   {
-  if (!rcmail_authenticate_session() ||
-      (!empty($CONFIG['session_lifetime']) && isset($SESS_CHANGED) && $SESS_CHANGED + $CONFIG['session_lifetime']*60 < mktime()))
+  if (!rcmail_authenticate_session())
     {
     $message = show_message('sessionerror', 'error');
     rcmail_kill_session();
diff --git a/program/include/main.inc b/program/include/main.inc
index 3fe196a..b6d995c 100644
--- a/program/include/main.inc
+++ b/program/include/main.inc
@@ -33,7 +33,7 @@
 // register session and connect to server
 function rcmail_startup($task='mail')
   {
-  global $sess_id, $sess_auth, $sess_user_lang;
+  global $sess_id, $sess_user_lang;
   global $CONFIG, $INSTALL_PATH, $BROWSER, $OUTPUT, $_SESSION, $IMAP, $DB, $JS_OBJECT_NAME;
 
   // check client
@@ -53,9 +53,8 @@
   $DB->sqlite_initials = $INSTALL_PATH.'SQL/sqlite.initial.sql';
   $DB->db_connect('w');
 
-  // we can use the database for storing session data
-  if (!$DB->is_error())
-    include_once('include/session.inc');
+  // use database for storing session data
+  include_once('include/session.inc');
 
   // init session
   session_start();
@@ -65,8 +64,8 @@
   if (!isset($_SESSION['auth_time']))
     {
     $_SESSION['user_lang'] = rcube_language_prop($CONFIG['locale_string']);
-    $_SESSION['auth_time'] = mktime();
-    setcookie('sessauth', rcmail_auth_hash($sess_id, $_SESSION['auth_time']));
+    $_SESSION['auth_time'] = time();
+    $_SESSION['temp'] = true;
     }
 
   // set session vars global
@@ -178,17 +177,29 @@
 // compare the auth hash sent by the client with the local session credentials
 function rcmail_authenticate_session()
   {
-  $now = mktime();
-  $valid = ($_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['auth_time']) ||
-						$_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['last_auth']));
+  global $CONFIG, $SESS_CLIENT_IP, $SESS_CHANGED;
+  
+  // advanced session authentication
+  if ($CONFIG['double_auth'])
+  {
+    $now = time();
+    $valid = ($_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['auth_time']) ||
+              $_COOKIE['sessauth'] == rcmail_auth_hash(session_id(), $_SESSION['last_auth']));
 
-  // renew auth cookie every 5 minutes (only for GET requests)
-  if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now-$_SESSION['auth_time'] > 300))
+    // renew auth cookie every 5 minutes (only for GET requests)
+    if (!$valid || ($_SERVER['REQUEST_METHOD']!='POST' && $now-$_SESSION['auth_time'] > 300))
     {
-    $_SESSION['last_auth'] = $_SESSION['auth_time'];
-    $_SESSION['auth_time'] = $now;
-    setcookie('sessauth', rcmail_auth_hash(session_id(), $now));
+      $_SESSION['last_auth'] = $_SESSION['auth_time'];
+      $_SESSION['auth_time'] = $now;
+      setcookie('sessauth', rcmail_auth_hash(session_id(), $now));
     }
+  }
+  else
+    $valid = $CONFIG['ip_check'] ? $_SERVER['REMOTE_ADDR'] == $SESS_CLIENT_IP : true;
+  
+  // check session filetime
+  if (!empty($CONFIG['session_lifetime']) && isset($SESS_CHANGED) && $SESS_CHANGED + $CONFIG['session_lifetime']*60 < time())
+    $valid = false;
 
   return $valid;
   }
@@ -275,8 +286,8 @@
     rcmail_save_user_prefs($a_user_prefs);
     }
 
-  $_SESSION = array();
-  session_destroy();
+  $_SESSION = array('user_lang' => $GLOBALS['sess_user_lang'], 'auth_time' => time(), 'temp' => true);
+  setcookie('sessauth', '-del-', time()-60);
   }
 
 
diff --git a/program/include/session.inc b/program/include/session.inc
index 6c4687e..59631af 100644
--- a/program/include/session.inc
+++ b/program/include/session.inc
@@ -36,7 +36,10 @@
 // read session data
 function sess_read($key)
   {
-  global $DB, $SESS_CHANGED;
+  global $DB, $SESS_CHANGED, $SESS_CLIENT_IP;
+  
+  if ($DB->is_error())
+    return FALSE;
   
   $sql_result = $DB->query("SELECT vars, ip, ".$DB->unixtimestamp('changed')." AS changed
                             FROM ".get_table_name('session')."
@@ -46,6 +49,7 @@
   if ($sql_arr = $DB->fetch_assoc($sql_result))
     {
     $SESS_CHANGED = $sql_arr['changed'];
+    $SESS_CLIENT_IP = $sql_arr['ip'];
 
     if (strlen($sql_arr['vars']))
       return $sql_arr['vars'];
@@ -59,6 +63,9 @@
 function sess_write($key, $vars)
   {
   global $DB;
+  
+  if ($DB->is_error())
+    return FALSE;
 
   $sql_result = $DB->query("SELECT 1
                             FROM ".get_table_name('session')."
@@ -96,6 +103,9 @@
   {
   global $DB;
   
+  if ($DB->is_error())
+    return FALSE;
+  
   // delete session entries in cache table
   $DB->query("DELETE FROM ".get_table_name('cache')."
               WHERE  session_id=?",
@@ -113,6 +123,9 @@
 function sess_gc($maxlifetime)
   {
   global $DB;
+
+  if ($DB->is_error())
+    return FALSE;
 
   // get all expired sessions  
   $sql_result = $DB->query("SELECT sess_id
@@ -144,6 +157,28 @@
   }
 
 
+function sess_regenerate_id()
+  {
+  $randlen = 32;
+  $randval = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  $random = "";
+  for ($i=1; $i <= $randlen; $i++)
+    $random .= substr($randval, rand(0,(strlen($randval) - 1)), 1);
+
+  // use md5 value for id or remove capitals from string $randval
+  $random = md5($random);
+
+  // delete old session record
+  sess_destroy(session_id());
+
+  session_id($random);
+  $cookie = session_get_cookie_params();
+  setcookie(session_name(), $random, $cookie['lifetime'], $cookie['path']);
+
+  return true;
+  }
+
+
 // set custom functions for PHP session management
 session_set_save_handler('sess_open', 'sess_close', 'sess_read', 'sess_write', 'sess_destroy', 'sess_gc');
 

--
Gitblit v1.9.1