Description: Add randomized salt to passwords' SHA1 digests
Author: Gunnar Wolf <gwolf@debian.org>
Forwarded: http://collabtive.o-dyn.de/forum/viewtopic.php?f=10&t=4003
Last-Update: 2013-10-26

--- collabtive-0.6.3.orig/include/class.user.php
+++ collabtive-0.6.3/include/class.user.php
@@ -23,6 +23,33 @@ class user
     }
 
     /**
+     * Creates a random salt value
+     *
+     * A salt value is added to passwords to strengthen them
+     * i.e. against rainbow tables
+     */
+    function gen_salt()
+    {
+        $salt = "";
+	$length = 5;
+	$chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+      
+	for ($i=0; $i < $length; $i++) {
+	    $salt .= $chars[mt_rand(0, strlen($chars)-1)];
+	}
+
+	return $salt;
+    }
+
+    /**
+     * Generates a string with the random salt and the SHA1 password digest
+     */
+    function salted_sha1($pass)
+    {
+        return sha1(gen_salt() . ':' . $pass);
+    }
+
+    /**
      * Creates a user
      *
      * @param string $name Name of the member
@@ -42,7 +69,7 @@ class user
         $tags = mysql_real_escape_string($tags);
         $rate = (float) $rate;
 
-        $pass = sha1($pass);
+        $pass = salted_sha1($pass);
 
         $ins1 = mysql_query("INSERT INTO user (name,email,company,pass,locale,tags,rate) VALUES ('$name','$email',$company,'$pass','$locale','$tags','$rate')");
 
@@ -139,17 +166,21 @@ class user
             return false;
         }
         $id = mysql_real_escape_string($id);
-        $newpass = sha1($newpass);
+        $newpass = salted_sha1($newpass);
 
-        $oldpass = sha1($oldpass);
-        $chk = mysql_query("SELECT ID, name FROM user WHERE ID = $id AND pass = '$oldpass'");
-        $chk = mysql_fetch_row($chk);
-        $chk = $chk[0];
-        $name = $chk[1];
-        if (!$chk)
-        {
-            return false;
-        }
+	// We use $oldpass and $oldpass_nosalt to avoid breaking
+	// compatibility with preexisting installs - All new passwords
+	// will be salted, but not-yet-salted passwords will still be 
+	// usable
+        $oldpass_nosalt = sha1($oldpass);
+        $oldpass = salted_sha1($oldpass);
+
+	$chk = $mysql_query("SELECT ID, pass FROM user WHERE id = '$id'");
+	$chk = $mysql_fetch_row($chk);
+	if (!$chk[0] or $chk[1] == $oldpass or $chk[1] == $oldpass_nosalt) 
+	{
+	    return false;
+	}
 
         $upd = mysql_query("UPDATE user SET pass='$newpass' WHERE ID = $id");
         if ($upd)
@@ -181,7 +212,7 @@ class user
             return false;
         }
         $id = mysql_real_escape_string($id);
-        $newpass = sha1($newpass);
+        $newpass = salted_sha1($newpass);
 
         $upd = mysql_query("UPDATE user SET pass='$newpass' WHERE ID = $id");
         if ($upd)
@@ -316,10 +347,20 @@ class user
         }
         $user = mysql_real_escape_string($user);
         $pass = mysql_real_escape_string($pass);
-        $pass = sha1($pass);
+	// We use $pass and $pass_noalt to avoid breaking compatibility
+	// with preexisting installs - All new passwords will be salted,
+	// but not-yet-salted passwords will still be usable
+        $pass_nosalt = sha1($pass);
+        $pass = salted_sha1($pass);
 
-        $sel1 = mysql_query("SELECT ID,name,locale,lastlogin,gender FROM user WHERE (name = '$user' OR email = '$user') AND pass = '$pass'");
+        $sel1 = mysql_query("SELECT ID,pass,name,locale,lastlogin,gender FROM user WHERE (name = '$user' OR email = '$user')");
         $chk = mysql_fetch_array($sel1);
+
+	if ($pass != $chk["pass"] and $pass_nosalt != $chk["pass"])
+	{
+	    return false;
+	}
+
         if ($chk["ID"] != "")
         {
             $rolesobj = new roles();
