Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F1820906
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Size
31 KB
Subscribers
None
View Options
diff --git a/PasswordHash.php b/PasswordHash.php
new file mode 100644
--- /dev/null
+++ b/PasswordHash.php
@@ -0,0 +1,253 @@
+<?php
+#
+# Portable PHP password hashing framework.
+#
+# Version 0.3 / genuine.
+#
+# Written by Solar Designer <solar at openwall.com> in 2004-2006 and placed in
+# the public domain. Revised in subsequent years, still public domain.
+#
+# There's absolutely no warranty.
+#
+# The homepage URL for this framework is:
+#
+# http://www.openwall.com/phpass/
+#
+# Please be sure to update the Version line if you edit this file in any way.
+# It is suggested that you leave the main version number intact, but indicate
+# your project name (after the slash) and add your own revision information.
+#
+# Please do not change the "private" password hashing method implemented in
+# here, thereby making your hashes incompatible. However, if you must, please
+# change the hash type identifier (the "$P$") to something different.
+#
+# Obviously, since this code is in the public domain, the above are not
+# requirements (there can be none), but merely suggestions.
+#
+class PasswordHash {
+ var $itoa64;
+ var $iteration_count_log2;
+ var $portable_hashes;
+ var $random_state;
+
+ function PasswordHash($iteration_count_log2, $portable_hashes)
+ {
+ $this->itoa64 = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
+
+ if ($iteration_count_log2 < 4 || $iteration_count_log2 > 31)
+ $iteration_count_log2 = 8;
+ $this->iteration_count_log2 = $iteration_count_log2;
+
+ $this->portable_hashes = $portable_hashes;
+
+ $this->random_state = microtime();
+ if (function_exists('getmypid'))
+ $this->random_state .= getmypid();
+ }
+
+ function get_random_bytes($count)
+ {
+ $output = '';
+ if (is_readable('/dev/urandom') &&
+ ($fh = @fopen('/dev/urandom', 'rb'))) {
+ $output = fread($fh, $count);
+ fclose($fh);
+ }
+
+ if (strlen($output) < $count) {
+ $output = '';
+ for ($i = 0; $i < $count; $i += 16) {
+ $this->random_state =
+ md5(microtime() . $this->random_state);
+ $output .=
+ pack('H*', md5($this->random_state));
+ }
+ $output = substr($output, 0, $count);
+ }
+
+ return $output;
+ }
+
+ function encode64($input, $count)
+ {
+ $output = '';
+ $i = 0;
+ do {
+ $value = ord($input[$i++]);
+ $output .= $this->itoa64[$value & 0x3f];
+ if ($i < $count)
+ $value |= ord($input[$i]) << 8;
+ $output .= $this->itoa64[($value >> 6) & 0x3f];
+ if ($i++ >= $count)
+ break;
+ if ($i < $count)
+ $value |= ord($input[$i]) << 16;
+ $output .= $this->itoa64[($value >> 12) & 0x3f];
+ if ($i++ >= $count)
+ break;
+ $output .= $this->itoa64[($value >> 18) & 0x3f];
+ } while ($i < $count);
+
+ return $output;
+ }
+
+ function gensalt_private($input)
+ {
+ $output = '$P$';
+ $output .= $this->itoa64[min($this->iteration_count_log2 +
+ ((PHP_VERSION >= '5') ? 5 : 3), 30)];
+ $output .= $this->encode64($input, 6);
+
+ return $output;
+ }
+
+ function crypt_private($password, $setting)
+ {
+ $output = '*0';
+ if (substr($setting, 0, 2) == $output)
+ $output = '*1';
+
+ $id = substr($setting, 0, 3);
+ # We use "$P$", phpBB3 uses "$H$" for the same thing
+ if ($id != '$P$' && $id != '$H$')
+ return $output;
+
+ $count_log2 = strpos($this->itoa64, $setting[3]);
+ if ($count_log2 < 7 || $count_log2 > 30)
+ return $output;
+
+ $count = 1 << $count_log2;
+
+ $salt = substr($setting, 4, 8);
+ if (strlen($salt) != 8)
+ return $output;
+
+ # We're kind of forced to use MD5 here since it's the only
+ # cryptographic primitive available in all versions of PHP
+ # currently in use. To implement our own low-level crypto
+ # in PHP would result in much worse performance and
+ # consequently in lower iteration counts and hashes that are
+ # quicker to crack (by non-PHP code).
+ if (PHP_VERSION >= '5') {
+ $hash = md5($salt . $password, TRUE);
+ do {
+ $hash = md5($hash . $password, TRUE);
+ } while (--$count);
+ } else {
+ $hash = pack('H*', md5($salt . $password));
+ do {
+ $hash = pack('H*', md5($hash . $password));
+ } while (--$count);
+ }
+
+ $output = substr($setting, 0, 12);
+ $output .= $this->encode64($hash, 16);
+
+ return $output;
+ }
+
+ function gensalt_extended($input)
+ {
+ $count_log2 = min($this->iteration_count_log2 + 8, 24);
+ # This should be odd to not reveal weak DES keys, and the
+ # maximum valid value is (2**24 - 1) which is odd anyway.
+ $count = (1 << $count_log2) - 1;
+
+ $output = '_';
+ $output .= $this->itoa64[$count & 0x3f];
+ $output .= $this->itoa64[($count >> 6) & 0x3f];
+ $output .= $this->itoa64[($count >> 12) & 0x3f];
+ $output .= $this->itoa64[($count >> 18) & 0x3f];
+
+ $output .= $this->encode64($input, 3);
+
+ return $output;
+ }
+
+ function gensalt_blowfish($input)
+ {
+ # This one needs to use a different order of characters and a
+ # different encoding scheme from the one in encode64() above.
+ # We care because the last character in our encoded string will
+ # only represent 2 bits. While two known implementations of
+ # bcrypt will happily accept and correct a salt string which
+ # has the 4 unused bits set to non-zero, we do not want to take
+ # chances and we also do not want to waste an additional byte
+ # of entropy.
+ $itoa64 = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+
+ $output = '$2a$';
+ $output .= chr(ord('0') + $this->iteration_count_log2 / 10);
+ $output .= chr(ord('0') + $this->iteration_count_log2 % 10);
+ $output .= '$';
+
+ $i = 0;
+ do {
+ $c1 = ord($input[$i++]);
+ $output .= $itoa64[$c1 >> 2];
+ $c1 = ($c1 & 0x03) << 4;
+ if ($i >= 16) {
+ $output .= $itoa64[$c1];
+ break;
+ }
+
+ $c2 = ord($input[$i++]);
+ $c1 |= $c2 >> 4;
+ $output .= $itoa64[$c1];
+ $c1 = ($c2 & 0x0f) << 2;
+
+ $c2 = ord($input[$i++]);
+ $c1 |= $c2 >> 6;
+ $output .= $itoa64[$c1];
+ $output .= $itoa64[$c2 & 0x3f];
+ } while (1);
+
+ return $output;
+ }
+
+ function HashPassword($password)
+ {
+ $random = '';
+
+ if (CRYPT_BLOWFISH == 1 && !$this->portable_hashes) {
+ $random = $this->get_random_bytes(16);
+ $hash =
+ crypt($password, $this->gensalt_blowfish($random));
+ if (strlen($hash) == 60)
+ return $hash;
+ }
+
+ if (CRYPT_EXT_DES == 1 && !$this->portable_hashes) {
+ if (strlen($random) < 3)
+ $random = $this->get_random_bytes(3);
+ $hash =
+ crypt($password, $this->gensalt_extended($random));
+ if (strlen($hash) == 20)
+ return $hash;
+ }
+
+ if (strlen($random) < 6)
+ $random = $this->get_random_bytes(6);
+ $hash =
+ $this->crypt_private($password,
+ $this->gensalt_private($random));
+ if (strlen($hash) == 34)
+ return $hash;
+
+ # Returning '*' on error is safe here, but would _not_ be safe
+ # in a crypt(3)-like function used _both_ for generating new
+ # hashes and for validating passwords against existing hashes.
+ return '*';
+ }
+
+ function CheckPassword($password, $stored_hash)
+ {
+ $hash = $this->crypt_private($password, $stored_hash);
+ if ($hash[0] == '*')
+ $hash = crypt($password, $stored_hash);
+
+ return $hash == $stored_hash;
+ }
+}
+
+?>
diff --git a/user_sql.php b/user_sql.php
--- a/user_sql.php
+++ b/user_sql.php
@@ -1,680 +1,684 @@
<?php
/**
* ownCloud - user_sql
*
* @author Andreas Böhler and contributors
* @copyright 2012/2013 Andreas Böhler <andreas (at) aboehler (dot) at>
*
* credits go to Ed W for several SQL injection fixes and caching support
* credits go to Frédéric France for providing Joomla support
* credits go to Mark Jansenn for providing Joomla 2.5.18+ / 3.2.1+ support
* credits go to Dominik Grothaus for providing SSHA256 support and fixing a few bugs
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE
* License as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU AFFERO GENERAL PUBLIC LICENSE for more details.
*
* You should have received a copy of the GNU Affero General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
class OC_USER_SQL extends OC_User_Backend implements OC_User_Interface
{
protected $cache;
// cached settings
protected $sql_host;
protected $sql_username;
protected $sql_database;
protected $sql_password;
protected $sql_table;
protected $sql_column_username;
protected $sql_column_password;
protected $sql_column_active;
protected $sql_column_displayname;
protected $sql_type;
protected $db_conn;
protected $db;
protected $default_domain;
protected $strip_domain;
protected $crypt_type;
protected $domain_settings;
protected $domain_array;
protected $map_array;
protected $allow_password_change;
public function __construct()
{
$this -> db_conn = false;
$this -> cache = \OC\Cache::getGlobalCache();
$this -> sql_host = OCP\Config::getAppValue('user_sql', 'sql_host', '');
$this -> sql_username = OCP\Config::getAppValue('user_sql', 'sql_user', '');
$this -> sql_database = OCP\Config::getAppValue('user_sql', 'sql_database', '');
$this -> sql_password = OCP\Config::getAppValue('user_sql', 'sql_password', '');
$this -> sql_table = OCP\Config::getAppValue('user_sql', 'sql_table', '');
$this -> sql_column_username = OCP\Config::getAppValue('user_sql', 'sql_column_username', '');
$this -> sql_column_password = OCP\Config::getAppValue('user_sql', 'sql_column_password', '');
$this -> sql_column_displayname = OCP\Config::getAppValue('user_sql', 'sql_column_displayname', $this->sql_column_username);
$this -> sql_column_active = OCP\Config::getAppValue('user_sql', 'sql_column_active', '');
$this -> sql_type = OCP\Config::getAppValue('user_sql', 'sql_type', '');
$this -> default_domain = OCP\Config::getAppValue('user_sql', 'default_domain', '');
$this -> strip_domain = OCP\Config::getAppValue('user_sql', 'strip_domain', 0);
$this -> allow_password_change = OCP\Config::getAppValue('user_sql', 'allow_password_change', 0);
$this -> crypt_type = OCP\Config::getAppValue('user_sql', 'crypt_type', 'md5crypt');
$this -> domain_settings = OCP\Config::getAppValue('user_sql', 'domain_settings', 'none');
$this -> domain_array = explode(",", OCP\Config::getAppValue('user_sql', 'domain_array', ''));
$this -> map_array = explode(",", OCP\Config::getAppValue('user_sql', 'map_array', ''));
$dsn = $this -> sql_type . ":host=" . $this -> sql_host . ";dbname=" . $this -> sql_database;
try
{
$this -> db = new PDO($dsn, $this -> sql_username, $this -> sql_password);
$this -> db_conn = true;
} catch (PDOException $e)
{
OC_Log::write('OC_USER_SQL', 'Failed to connect to the database: ' . $e -> getMessage(), OC_Log::ERROR);
}
return false;
}
private function doUserDomainMapping($uid)
{
$uid = trim($uid);
switch($this->domain_settings)
{
case "default" :
OC_Log::write('OC_USER_SQL', "Default mapping", OC_Log::DEBUG);
if($this -> default_domain && (strpos($uid, '@') === false))
$uid .= "@" . $this -> default_domain;
break;
case "server" :
OC_Log::write('OC_USER_SQL', "Server based mapping", OC_Log::DEBUG);
if(strpos($uid, '@') === false)
$uid .= "@" . $_SERVER['SERVER_NAME'];
break;
case "mapping" :
OC_Log::write('OC_USER_SQL', 'Domain mapping selected', OC_Log::DEBUG);
if(strpos($uid, '@') === false)
{
for($i = 0; $i < count($this -> domain_array); $i++)
{
OC_Log::write('OC_USER_SQL', 'Checking domain in mapping: ' . $this -> domain_array[$i], OC_Log::DEBUG);
if($_SERVER['SERVER_NAME'] == trim($this -> domain_array[$i]))
{
OC_Log::write('OC_USER_SQL', 'Found domain in mapping: ' . $this -> domain_array[$i], OC_Log::DEBUG);
$uid .= "@" . trim($this -> map_array[$i]);
break;
}
}
}
break;
case "none" :
default :
OC_Log::write('OC_USER_SQL', "No mapping", OC_Log::DEBUG);
break;
}
$uid = strtolower($uid);
OC_Log::write('OC_USER_SQL', 'Returning mapped UID: ' . $uid, OC_Log::DEBUG);
return $uid;
}
public function implementsAction($actions)
{
return (bool)((OC_USER_BACKEND_CHECK_PASSWORD | OC_USER_BACKEND_GET_DISPLAYNAME) & $actions);
}
public function hasUserListings()
{
return true;
}
public function createUser()
{
// Can't create user
OC_Log::write('OC_USER_SQL', 'Not possible to create local users from web frontend using SQL user backend', OC_Log::ERROR);
return false;
}
public function deleteUser($uid)
{
// Can't delete user
OC_Log::write('OC_USER_SQL', 'Not possible to delete local users from web frontend using SQL user backend', OC_Log::ERROR);
return false;
}
public function setPassword($uid, $password)
{
// Update the user's password - this might affect other services, that
// use the same database, as well
OC_Log::write('OC_USER_SQL', "Entering setPassword for UID: $uid", OC_Log::DEBUG);
if(!$this -> db_conn || !$this->allow_password_change)
{
return false;
}
$uid = $this -> doUserDomainMapping($uid);
$query = "SELECT $this->sql_column_password FROM $this->sql_table WHERE $this->sql_column_username = :uid";
OC_Log::write('OC_USER_SQL', "Preparing query: $query", OC_Log::DEBUG);
$result = $this -> db -> prepare($query);
$result -> bindParam(":uid", $uid);
OC_Log::write('OC_USER_SQL', "Executing query...", OC_Log::DEBUG);
if(!$result -> execute())
{
return false;
}
OC_Log::write('OC_USER_SQL', "Fetching result...", OC_Log::DEBUG);
$row = $result -> fetch();
if(!$row)
{
return false;
}
$old_password = $row[$this -> sql_column_password];
if($this -> crypt_type == 'joomla2')
{
+ if(!class_exists('PasswordHash')
+ require_once('PasswordHash.php');
$hasher = new PasswordHash(10, true);
$enc_password = $hasher->HashPassword($password);
} else
{
$enc_password = $this -> pacrypt($password, $old_password);
}
$query = "UPDATE $this->sql_table SET $this->sql_column_password = :enc_password WHERE $this->sql_column_username = :uid";
OC_Log::write('OC_USER_SQL', "Preapring query: $query", OC_Log::DEBUG);
$result = $this -> db -> prepare($query);
$result -> bindParam(":enc_password", $enc_password);
$result -> bindParam(":uid", $uid);
OC_Log::write('OC_USER_SQL', "Executing query...", OC_Log::DEBUG);
if(!$result -> execute())
{
$err = $result -> errorInfo();
OC_Log::write('OC_USER_SQL', "Query failed: " . $err[2], OC_Log::DEBUG);
OC_Log::write('OC_USER_SQL', "Could not update password!", OC_Log::ERROR);
return false;
}
OC_Log::write('OC_USER_SQL', "Updated password successfully, return true", OC_Log::DEBUG);
return true;
}
/**
* @brief Check if the password is correct
* @param $uid The username
* @param $password The password
* @returns true/false
*
* Check if the password is correct without logging in the user
*/
public function checkPassword($uid, $password)
{
OC_Log::write('OC_USER_SQL', "Entering checkPassword() for UID: $uid", OC_Log::DEBUG);
if(!$this -> db_conn)
{
return false;
}
$uid = $this -> doUserDomainMapping($uid);
$query = "SELECT $this->sql_column_username, $this->sql_column_password FROM $this->sql_table WHERE $this->sql_column_username = :uid";
if($this -> sql_column_active != '')
$query .= " AND $this->sql_column_active = 1";
OC_Log::write('OC_USER_SQL', "Preparing query: $query", OC_Log::DEBUG);
$result = $this -> db -> prepare($query);
$result -> bindParam(":uid", $uid);
OC_Log::write('OC_USER_SQL', "Executing query...", OC_Log::DEBUG);
if(!$result -> execute())
{
$err = $result -> errorInfo();
OC_Log::write('OC_USER_SQL', "Query failed: " . $err[2], OC_Log::DEBUG);
return false;
}
OC_Log::write('OC_USER_SQL', "Fetching row...", OC_Log::DEBUG);
$row = $result -> fetch();
if(!$row)
{
OC_Log::write('OC_USER_SQL', "Got no row, return false", OC_Log::DEBUG);
return false;
}
OC_Log::write('OC_USER_SQL', "Encrypting and checking password", OC_Log::DEBUG);
// Joomla 2.5.18 switched to phPass, which doesn't play nice with the way
// we check passwords
if($this -> crypt_type == 'joomla2')
{
+ if(!class_exists('PasswordHash'))
+ require_once('PasswordHash.php');
$hasher = new PasswordHash(10, true);
$ret = $hasher -> CheckPassword($password, $row[$this -> sql_column_password]);
} else
{
$ret = $this -> pacrypt($password, $row[$this -> sql_column_password]) == $row[$this -> sql_column_password];
}
if($ret)
{
OC_Log::write('OC_USER_SQL', "Passwords matching, return true", OC_Log::DEBUG);
if($this -> strip_domain)
{
$uid = explode("@", $uid);
$uid = $uid[0];
}
return $uid;
} else
{
OC_Log::write('OC_USER_SQL', "Passwords do not match, return false", OC_Log::DEBUG);
return false;
}
}
/**
* @brief Get a list of all users
* @returns array with all uids
*
* Get a list of all users.
*/
public function getUsers($search = '', $limit = null, $offset = null)
{
OC_Log::write('OC_USER_SQL', "Entering getUsers() with Search: $search, Limit: $limit, Offset: $offset", OC_Log::DEBUG);
$users = array();
if(!$this -> db_conn)
{
return false;
}
$query = "SELECT $this->sql_column_username FROM $this->sql_table";
$query .= " WHERE $this->sql_column_username LIKE :search";
if($this -> sql_column_active != '')
{
$query .= " AND $this->sql_column_active = 1";
}
$query .= " ORDER BY $this->sql_column_username";
if($limit != null)
{
$limit = intval($limit);
$query .= " LIMIT $limit";
}
if($offset != null)
{
$offset = intval($offset);
$query .= " OFFSET $offset";
}
OC_Log::write('OC_USER_SQL', "Preparing query: $query", OC_Log::DEBUG);
$result = $this -> db -> prepare($query);
if($search != '')
{
$search = "%".$this -> doUserDomainMapping($search."%")."%";
}
else
{
$search = "%".$this -> doUserDomainMapping("")."%";
}
$result -> bindParam(":search", $search);
OC_Log::write('OC_USER_SQL', "Executing query...", OC_Log::DEBUG);
if(!$result -> execute())
{
$err = $result -> errorInfo();
OC_Log::write('OC_USER_SQL', "Query failed: " . $err[2], OC_Log::DEBUG);
return array();
}
OC_Log::write('OC_USER_SQL', "Fetching results...", OC_Log::DEBUG);
while($row = $result -> fetch())
{
$uid = $row[$this -> sql_column_username];
if($this -> strip_domain)
{
$uid = explode("@", $uid);
$uid = $uid[0];
}
$users[] = strtolower($uid);
}
OC_Log::write('OC_USER_SQL', "Return list of results", OC_Log::DEBUG);
return $users;
}
/**
* @brief check if a user exists
* @param string $uid the username
* @return boolean
*/
public function userExists($uid)
{
$cacheKey = 'sql_user_exists_' . $uid;
$cacheVal = $this -> cache -> get($cacheKey);
if(!is_null($cacheVal))
return (bool)$cacheVal;
OC_Log::write('OC_USER_SQL', "Entering userExists() for UID: $uid", OC_Log::DEBUG);
if(!$this -> db_conn)
{
return false;
}
$uid = $this -> doUserDomainMapping($uid);
$query = "SELECT $this->sql_column_username FROM $this->sql_table WHERE $this->sql_column_username = :uid";
if($this -> sql_column_active != '')
$query .= " AND $this->sql_column_active = 1";
OC_Log::write('OC_USER_SQL', "Preparing query: $query", OC_Log::DEBUG);
$result = $this -> db -> prepare($query);
$result -> bindParam(":uid", $uid);
OC_Log::write('OC_USER_SQL', "Executing query...", OC_Log::DEBUG);
if(!$result -> execute())
{
$err = $result -> errorInfo();
OC_Log::write('OC_USER_SQL', "Query failed: " . $err[2], OC_Log::DEBUG);
return false;
}
OC_Log::write('OC_USER_SQL', "Fetching results...", OC_Log::DEBUG);
$exists = (bool)$result -> fetch();
$this -> cache -> set($cacheKey, $exists, 60);
if(!$exists)
{
OC_Log::write('OC_USER_SQL', "Empty row, user does not exists, return false", OC_Log::DEBUG);
return false;
} else
{
OC_Log::write('OC_USER_SQL', "User exists, return true", OC_Log::DEBUG);
return true;
}
}
public function getDisplayName($uid)
{
OC_Log::write('OC_USER_SQL', "Entering getDisplayName() for UID: $uid", OC_Log::DEBUG);
if(!$this -> db_conn)
{
return false;
}
$uid = $this -> doUserDomainMapping($uid);
if(!$this -> userExists($uid))
{
return false;
}
$query = "SELECT $this->sql_column_displayname FROM $this->sql_table WHERE $this->sql_column_username = :uid";
if($this -> sql_column_active != '')
$query .= " AND $this->sql_column_active = 1";
OC_Log::write('OC_USER_SQL', "Preparing query: $query", OC_Log::DEBUG);
$result = $this -> db -> prepare($query);
$result -> bindParam(":uid", $uid);
OC_Log::write('OC_USER_SQL', "Executing query...", OC_Log::DEBUG);
if(!$result -> execute())
{
$err = $result -> errorInfo();
OC_Log::write('OC_USER_SQL', "Query failed: " . $err[2], OC_Log::DEBUG);
return false;
}
OC_Log::write('OC_USER_SQL', "Fetching results...", OC_Log::DEBUG);
$row = $result -> fetch();
if(!$row)
{
OC_Log::write('OC_USER_SQL', "Empty row, user has no display name or does not exist, return false", OC_Log::DEBUG);
return false;
} else
{
OC_Log::write('OC_USER_SQL', "User exists, return true", OC_Log::DEBUG);
$displayName = utf8_encode($row[$this -> sql_column_displayname]);
return $displayName; ;
}
return false;
}
public function getDisplayNames($search = '', $limit = null, $offset = null)
{
$uids = $this -> getUsers($search, $limit, $offset);
$displayNames = array();
foreach($uids as $uid)
{
$displayNames[$uid] = $this -> getDisplayName($uid);
}
return $displayNames;
}
/**
* The following functions were directly taken from PostfixAdmin and just
* slightly modified
* to suit our needs.
* Encrypt a password, using the apparopriate hashing mechanism as defined in
* config.inc.php ($this->crypt_type).
* When wanting to compare one pw to another, it's necessary to provide the
* salt used - hence
* the second parameter ($pw_db), which is the existing hash from the DB.
*
* @param string $pw
* @param string $encrypted password
* @return string encrypted password.
*/
private function pacrypt($pw, $pw_db = "")
{
OC_Log::write('OC_USER_SQL', "Entering private pacrypt()", OC_Log::DEBUG);
$pw = stripslashes($pw);
$password = "";
$salt = "";
if($this -> crypt_type == 'md5crypt')
{
$split_salt = preg_split('/\$/', $pw_db);
if(isset($split_salt[2]))
{
$salt = $split_salt[2];
}
$password = $this -> md5crypt($pw, $salt);
} elseif($this -> crypt_type == 'md5')
{
$password = md5($pw);
} elseif($this -> crypt_type == 'system')
{
// We never generate salts, as user creation is not allowed here
$password = crypt($pw, $pw_db);
} elseif($this -> crypt_type == 'cleartext')
{
$password = $pw;
}
// See
// https://sourceforge.net/tracker/?func=detail&atid=937966&aid=1793352&group_id=191583
// this is apparently useful for pam_mysql etc.
elseif($this -> crypt_type == 'mysql_encrypt')
{
if(!$this -> db_conn)
{
return false;
}
if($pw_db != "")
{
$salt = substr($pw_db, 0, 2);
$query = "SELECT ENCRYPT(:pw, :salt);";
} else
{
$query = "SELECT ENCRYPT(:pw);";
}
$result = $this -> db -> prepare($query);
$result -> bindParam(":pw", $pw);
if($pw_db != "")
$result -> bindParam(":salt", $salt);
if(!$result -> execute())
{
return false;
}
$row = $result -> fetch();
if(!$row)
{
return false;
}
$password = $row[0];
} elseif($this -> crypt_type == 'mysql_password')
{
if(!$this -> db_conn)
{
return false;
}
$query = "SELECT PASSWORD(:pw);";
$result = $this -> db -> prepare($query);
$result -> bindParam(":pw", $pw);
if(!$result -> execute())
{
return false;
}
$row = $result -> fetch();
if(!$row)
{
return false;
}
$password = $row[0];
}
// The following is by Frédéric France
elseif($this -> crypt_type == 'joomla')
{
$split_salt = preg_split('/:/', $pw_db);
if(isset($split_salt[1]))
{
$salt = $split_salt[1];
}
$password = ($salt) ? md5($pw . $salt) : md5($pw);
$password .= ':' . $salt;
}
elseif($this-> crypt_type == 'ssha256')
{
$salted_password = base64_decode(preg_replace('/{SSHA256}/i','',$pw_db));
$salt = substr($salted_password,-(strlen($salted_password)-32));
$password = $this->ssha256($pw,$salt);
} else
{
OC_Log::write('OC_USER_SQL', "unknown/invalid crypt_type settings: $this->crypt_type", OC_Log::ERROR);
die('unknown/invalid Encryption type setting: ' . $this -> crypt_type);
}
OC_Log::write('OC_USER_SQL', "pacrypt() done, return", OC_Log::DEBUG);
return $password;
}
//
// md5crypt
// Action: Creates MD5 encrypted password
// Call: md5crypt (string cleartextpassword)
//
private function md5crypt($pw, $salt = "", $magic = "")
{
$MAGIC = "$1$";
if($magic == "")
$magic = $MAGIC;
if($salt == "")
$salt = $this -> create_salt();
$slist = explode("$", $salt);
if($slist[0] == "1")
$salt = $slist[1];
$salt = substr($salt, 0, 8);
$ctx = $pw . $magic . $salt;
$final = $this -> pahex2bin(md5($pw . $salt . $pw));
for($i = strlen($pw); $i > 0; $i -= 16)
{
if($i > 16)
{
$ctx .= substr($final, 0, 16);
} else
{
$ctx .= substr($final, 0, $i);
}
}
$i = strlen($pw);
while($i > 0)
{
if($i & 1)
$ctx .= chr(0);
else
$ctx .= $pw[0];
$i = $i>>1;
}
$final = $this -> pahex2bin(md5($ctx));
for($i = 0; $i < 1000; $i++)
{
$ctx1 = "";
if($i & 1)
{
$ctx1 .= $pw;
} else
{
$ctx1 .= substr($final, 0, 16);
}
if($i % 3)
$ctx1 .= $salt;
if($i % 7)
$ctx1 .= $pw;
if($i & 1)
{
$ctx1 .= substr($final, 0, 16);
} else
{
$ctx1 .= $pw;
}
$final = $this -> pahex2bin(md5($ctx1));
}
$passwd = "";
$passwd .= $this -> to64(((ord($final[0])<<16) | (ord($final[6])<<8) | (ord($final[12]))), 4);
$passwd .= $this -> to64(((ord($final[1])<<16) | (ord($final[7])<<8) | (ord($final[13]))), 4);
$passwd .= $this -> to64(((ord($final[2])<<16) | (ord($final[8])<<8) | (ord($final[14]))), 4);
$passwd .= $this -> to64(((ord($final[3])<<16) | (ord($final[9])<<8) | (ord($final[15]))), 4);
$passwd .= $this -> to64(((ord($final[4])<<16) | (ord($final[10])<<8) | (ord($final[5]))), 4);
$passwd .= $this -> to64(ord($final[11]), 2);
return "$magic$salt\$$passwd";
}
private function create_salt()
{
srand((double) microtime() * 1000000);
$salt = substr(md5(rand(0, 9999999)), 0, 8);
return $salt;
}
private function ssha256($pw, $salt)
{
return '{SSHA256}'.base64_encode(hash('sha256',$pw.$salt,true).$salt);
}
private function pahex2bin($str)
{
if(function_exists('hex2bin'))
{
return hex2bin($str);
} else
{
$len = strlen($str);
$nstr = "";
for($i = 0; $i < $len; $i += 2)
{
$num = sscanf(substr($str, $i, 2), "%x");
$nstr .= chr($num[0]);
}
return $nstr;
}
}
private function to64($v, $n)
{
$ITOA64 = "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
$ret = "";
while(($n - 1) >= 0)
{
$n--;
$ret .= $ITOA64[$v & 0x3f];
$v = $v>>6;
}
return $ret;
}
}
?>
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Sun, Dec 22, 9:27 PM (2 d, 10 h ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
528034
Default Alt Text
(31 KB)
Attached To
rUSQL ownCloud user_sql PlugIn
Event Timeline
Log In to Comment