Page MenuHomePhorge

No OneTemporary

Size
81 KB
Referenced Files
None
Subscribers
None
diff --git a/plugins/password/composer.json b/plugins/password/composer.json
index 3aba2a2ba..743d15e10 100644
--- a/plugins/password/composer.json
+++ b/plugins/password/composer.json
@@ -1,24 +1,24 @@
{
"name": "roundcube/password",
"type": "roundcube-plugin",
"description": "Password Change for Roundcube. Plugin adds a possibility to change user password using many methods (drivers) via Settings/Password tab.",
"license": "GPLv3+",
- "version": "3.5",
+ "version": "4.0",
"authors": [
{
"name": "Aleksander Machniak",
"email": "alec@alec.pl",
"role": "Lead"
}
],
"repositories": [
{
"type": "composer",
"url": "http://plugins.roundcube.net"
}
],
"require": {
"php": ">=5.3.0",
"roundcube/plugin-installer": ">=0.1.3"
}
}
diff --git a/plugins/password/config.inc.php.dist b/plugins/password/config.inc.php.dist
index af87a8361..0b004b876 100644
--- a/plugins/password/config.inc.php.dist
+++ b/plugins/password/config.inc.php.dist
@@ -1,406 +1,420 @@
<?php
// Password Plugin options
// -----------------------
// A driver to use for password change. Default: "sql".
// See README file for list of supported driver names.
$config['password_driver'] = 'sql';
// Determine whether current password is required to change password.
// Default: false.
$config['password_confirm_current'] = true;
// Require the new password to be a certain length.
// set to blank to allow passwords of any length
$config['password_minimum_length'] = 0;
// Require the new password to contain a letter and punctuation character
// Change to false to remove this check.
$config['password_require_nonalpha'] = false;
// Enables logging of password changes into logs/password
$config['password_log'] = false;
// Comma-separated list of login exceptions for which password change
// will be not available (no Password tab in Settings)
$config['password_login_exceptions'] = null;
// Array of hosts that support password changing. Default is NULL.
// Listed hosts will feature a Password option in Settings; others will not.
-// Example:
-//$config['password_hosts'] = array('mail.example.com', 'mail2.example.org');
+// Example: array('mail.example.com', 'mail2.example.org');
$config['password_hosts'] = null;
// Enables saving the new password even if it matches the old password. Useful
// for upgrading the stored passwords after the encryption scheme has changed.
$config['password_force_save'] = false;
// Enables forcing new users to change their password at their first login.
$config['password_force_new_user'] = false;
+// Default password hashing/crypting algorithm.
+// Possible options: des-crypt, ext-des-crypt, md5-crypt, blowfish-crypt,
+// sha256-crypt, sha512-crypt, md5, sha, smd5, ssha, samba, ad, dovecot, clear.
+// For details see password::hash_password() method.
+$config['password_algorithm'] = 'clear';
+
+// Password prefix (e.g. {CRYPT}, {SHA}) for passwords generated
+// using password_algorithm above. Default: empty.
+$config['password_algorithm_prefix'] = '';
+
+// Path for dovecotpw/doveadm-pw (if not in $PATH)
+// Used for password_algorithm = 'dovecot'.
+// $config['password_dovecotpw'] = '/usr/local/sbin/dovecotpw';
+
+// Dovecot method (dovecotpw -s 'method')
+// Used for password_algorithm = 'dovecot'.
+$config['password_dovecotpw_method'] = 'CRAM-MD5';
+
+// Iteration count parameter for Blowfish-based hashing algo.
+// It must be between 4 and 31. Default: 12.
+// Be aware, the higher the value, the longer it takes to generate the password hashes.
+$config['password_blowfish_cost'] = 12;
+
+
// SQL Driver options
// ------------------
// PEAR database DSN for performing the query. By default
// Roundcube DB settings are used.
$config['password_db_dsn'] = '';
// The SQL query used to change the password.
// The query can contain the following macros that will be expanded as follows:
// %p is replaced with the plaintext new password
-// %c is replaced with the crypt version of the new password, MD5 if available
-// otherwise DES. More hash function can be enabled using the password_crypt_hash
-// configuration parameter.
-// %D is replaced with the dovecotpw-crypted version of the new password
-// %o is replaced with the password before the change
-// %n is replaced with the hashed version of the new password
-// %q is replaced with the hashed password before the change
+// %P is replaced with the crypted/hashed new password
+// according to configured password_method
+// %o is replaced with the old (current) password
+// %O is replaced with the crypted/hashed old (current) password
+// according to configured password_method
// %h is replaced with the imap host (from the session info)
// %u is replaced with the username (from the session info)
// %l is replaced with the local part of the username
// (in case the username is an email address)
// %d is replaced with the domain part of the username
// (in case the username is an email address)
+// Deprecated macros:
+// %c is replaced with the crypt version of the new password, MD5 if available
+// otherwise DES. More hash function can be enabled using the password_crypt_hash
+// configuration parameter.
+// %D is replaced with the dovecotpw-crypted version of the new password
+// %n is replaced with the hashed version of the new password
+// %q is replaced with the hashed password before the change
// Escaping of macros is handled by this module.
// Default: "SELECT update_passwd(%c, %u)"
$config['password_query'] = 'SELECT update_passwd(%c, %u)';
-// By default the crypt() function which is used to create the '%c'
-// parameter uses the md5 algorithm. To use different algorithms
-// you can choose between: des, md5, blowfish, sha256, sha512.
-// Before using other hash functions than des or md5 please make sure
-// your operating system supports the other hash functions.
+// By default the crypt() function which is used to create the %c
+// parameter uses the md5 algorithm (deprecated, use %P).
+// You can choose between: des, md5, blowfish, sha256, sha512.
$config['password_crypt_hash'] = 'md5';
// By default domains in variables are using unicode.
// Enable this option to use punycoded names
$config['password_idn_ascii'] = false;
-// Path for dovecotpw (if not in $PATH)
-// $config['password_dovecotpw'] = '/usr/local/sbin/dovecotpw';
-
-// Dovecot method (dovecotpw -s 'method')
-$config['password_dovecotpw_method'] = 'CRAM-MD5';
-
// Enables use of password with crypt method prefix in %D, e.g. {MD5}$1$LUiMYWqx$fEkg/ggr/L6Mb2X7be4i1/
+// when using the %D macro (deprecated, use %P)
$config['password_dovecotpw_with_method'] = false;
-// Using a password hash for %n and %q variables.
+// Using a password hash for %n and %q variables (deprecated, use %P).
// Determine which hashing algorithm should be used to generate
// the hashed new and current password for using them within the
// SQL query. Requires PHP's 'hash' extension.
$config['password_hash_algorithm'] = 'sha1';
// You can also decide whether the hash should be provided
// as hex string or in base64 encoded format.
$config['password_hash_base64'] = false;
-// Iteration count parameter for Blowfish-based hashing algo.
-// It must be between 4 and 31. Default: 12.
-// Be aware, the higher the value, the longer it takes to generate the password hashes.
-$config['password_blowfish_cost'] = 12;
-
// Poppassd Driver options
// -----------------------
// The host which changes the password
$config['password_pop_host'] = 'localhost';
// TCP port used for poppassd connections
$config['password_pop_port'] = 106;
// SASL Driver options
// -------------------
// Additional arguments for the saslpasswd2 call
$config['password_saslpasswd_args'] = '';
// LDAP and LDAP_SIMPLE Driver options
// -----------------------------------
// LDAP server name to connect to.
// You can provide one or several hosts in an array in which case the hosts are tried from left to right.
// Exemple: array('ldap1.exemple.com', 'ldap2.exemple.com');
// Default: 'localhost'
$config['password_ldap_host'] = 'localhost';
// LDAP server port to connect to
// Default: '389'
$config['password_ldap_port'] = '389';
// TLS is started after connecting
// Using TLS for password modification is recommanded.
// Default: false
$config['password_ldap_starttls'] = false;
// LDAP version
// Default: '3'
$config['password_ldap_version'] = '3';
// LDAP base name (root directory)
// Exemple: 'dc=exemple,dc=com'
$config['password_ldap_basedn'] = 'dc=exemple,dc=com';
// LDAP connection method
// There is two connection method for changing a user's LDAP password.
// 'user': use user credential (recommanded, require password_confirm_current=true)
// 'admin': use admin credential (this mode require password_ldap_adminDN and password_ldap_adminPW)
// Default: 'user'
$config['password_ldap_method'] = 'user';
// LDAP Admin DN
// Used only in admin connection mode
// Default: null
$config['password_ldap_adminDN'] = null;
// LDAP Admin Password
// Used only in admin connection mode
// Default: null
$config['password_ldap_adminPW'] = null;
// LDAP user DN mask
// The user's DN is mandatory and as we only have his login,
// we need to re-create his DN using a mask
// '%login' will be replaced by the current roundcube user's login
// '%name' will be replaced by the current roundcube user's name part
// '%domain' will be replaced by the current roundcube user's domain part
// '%dc' will be replaced by domain name hierarchal string e.g. "dc=test,dc=domain,dc=com"
// Exemple: 'uid=%login,ou=people,dc=exemple,dc=com'
$config['password_ldap_userDN_mask'] = 'uid=%login,ou=people,dc=exemple,dc=com';
// LDAP search DN
// The DN roundcube should bind with to find out user's DN
// based on his login. Note that you should comment out the default
// password_ldap_userDN_mask setting for this to take effect.
// Use this if you cannot specify a general template for user DN with
// password_ldap_userDN_mask. You need to perform a search based on
// users login to find his DN instead. A common reason might be that
// your users are placed under different ou's like engineering or
// sales which cannot be derived from their login only.
$config['password_ldap_searchDN'] = 'cn=roundcube,ou=services,dc=example,dc=com';
// LDAP search password
// If password_ldap_searchDN is set, the password to use for
// binding to search for user's DN. Note that you should comment out the default
// password_ldap_userDN_mask setting for this to take effect.
// Warning: Be sure to set approperiate permissions on this file so this password
// is only accesible to roundcube and don't forget to restrict roundcube's access to
// your directory as much as possible using ACLs. Should this password be compromised
// you want to minimize the damage.
$config['password_ldap_searchPW'] = 'secret';
// LDAP search base
// If password_ldap_searchDN is set, the base to search in using the filter below.
// Note that you should comment out the default password_ldap_userDN_mask setting
// for this to take effect.
$config['password_ldap_search_base'] = 'ou=people,dc=example,dc=com';
// LDAP search filter
// If password_ldap_searchDN is set, the filter to use when
// searching for user's DN. Note that you should comment out the default
// password_ldap_userDN_mask setting for this to take effect.
// '%login' will be replaced by the current roundcube user's login
// '%name' will be replaced by the current roundcube user's name part
// '%domain' will be replaced by the current roundcube user's domain part
// '%dc' will be replaced by domain name hierarchal string e.g. "dc=test,dc=domain,dc=com"
// Example: '(uid=%login)'
// Example: '(&(objectClass=posixAccount)(uid=%login))'
$config['password_ldap_search_filter'] = '(uid=%login)';
// LDAP password hash type
// Standard LDAP encryption type which must be one of: crypt,
// ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, ad, cram-md5 (dovecot style) or clear.
-// Please note that most encodage types require external libraries
-// to be included in your PHP installation, see function hashPassword in drivers/ldap.php for more info.
+// Set to 'default' if you want to use method specified in password_algorithm option above.
// Multiple password Values can be generated by concatenating encodings with a +. E.g. 'cram-md5+crypt'
// Default: 'crypt'.
$config['password_ldap_encodage'] = 'crypt';
// LDAP password attribute
// Name of the ldap's attribute used for storing user password
// Default: 'userPassword'
$config['password_ldap_pwattr'] = 'userPassword';
// LDAP password force replace
// Force LDAP replace in cases where ACL allows only replace not read
// See http://pear.php.net/package/Net_LDAP2/docs/latest/Net_LDAP2/Net_LDAP2_Entry.html#methodreplace
// Default: true
$config['password_ldap_force_replace'] = true;
// LDAP Password Last Change Date
// Some places use an attribute to store the date of the last password change
// The date is meassured in "days since epoch" (an integer value)
// Whenever the password is changed, the attribute will be updated if set (e.g. shadowLastChange)
$config['password_ldap_lchattr'] = '';
// LDAP Samba password attribute, e.g. sambaNTPassword
// Name of the LDAP's Samba attribute used for storing user password
$config['password_ldap_samba_pwattr'] = '';
// LDAP Samba Password Last Change Date attribute, e.g. sambaPwdLastSet
// Some places use an attribute to store the date of the last password change
// The date is meassured in "seconds since epoch" (an integer value)
// Whenever the password is changed, the attribute will be updated if set
$config['password_ldap_samba_lchattr'] = '';
// DirectAdmin Driver options
// --------------------------
// The host which changes the password
// Use 'ssl://host' instead of 'tcp://host' when running DirectAdmin over SSL.
// The host can contain the following macros that will be expanded as follows:
// %h is replaced with the imap host (from the session info)
// %d is replaced with the domain part of the username (if the username is an email)
$config['password_directadmin_host'] = 'tcp://localhost';
// TCP port used for DirectAdmin connections
$config['password_directadmin_port'] = 2222;
// vpopmaild Driver options
// -----------------------
// The host which changes the password
$config['password_vpopmaild_host'] = 'localhost';
// TCP port used for vpopmaild connections
$config['password_vpopmaild_port'] = 89;
// Timout used for the connection to vpopmaild (in seconds)
$config['password_vpopmaild_timeout'] = 10;
// cPanel Driver options
// --------------------------
// The cPanel Host name
$config['password_cpanel_host'] = 'host.domain.com';
// The cPanel admin username
$config['password_cpanel_username'] = 'username';
// The cPanel admin password
$config['password_cpanel_password'] = 'password';
// The cPanel port to use
$config['password_cpanel_port'] = 2087;
// XIMSS (Communigate server) Driver options
// -----------------------------------------
// Host name of the Communigate server
$config['password_ximss_host'] = 'mail.example.com';
// XIMSS port on Communigate server
$config['password_ximss_port'] = 11024;
// chpasswd Driver options
// ---------------------
// Command to use (see "Sudo setup" in README)
$config['password_chpasswd_cmd'] = 'sudo /usr/sbin/chpasswd 2> /dev/null';
// XMail Driver options
// ---------------------
$config['xmail_host'] = 'localhost';
$config['xmail_user'] = 'YourXmailControlUser';
$config['xmail_pass'] = 'YourXmailControlPass';
$config['xmail_port'] = 6017;
// hMail Driver options
// -----------------------
// Remote hMailServer configuration
// true: HMailserver is on a remote box (php.ini: com.allow_dcom = true)
// false: Hmailserver is on same box as PHP
$config['hmailserver_remote_dcom'] = false;
// Windows credentials
$config['hmailserver_server'] = array(
- 'Server' => 'localhost', // hostname or ip address
- 'Username' => 'administrator', // windows username
- 'Password' => 'password' // windows user password
+ 'Server' => 'localhost', // hostname or ip address
+ 'Username' => 'administrator', // windows username
+ 'Password' => 'password' // windows user password
);
// Virtualmin Driver options
// -------------------------
// Username format:
// 0: username@domain
// 1: username%domain
// 2: username.domain
// 3: domain.username
// 4: username-domain
// 5: domain-username
// 6: username_domain
// 7: domain_username
$config['password_virtualmin_format'] = 0;
// pw_usermod Driver options
// --------------------------
// Use comma delimited exlist to disable password change for users.
// See "Sudo setup" in README file.
$config['password_pw_usermod_cmd'] = 'sudo /usr/sbin/pw usermod -h 0 -n';
// DBMail Driver options
// -------------------
// Additional arguments for the dbmail-users call
$config['password_dbmail_args'] = '-p sha512';
// Expect Driver options
// ---------------------
// Location of expect binary
$config['password_expect_bin'] = '/usr/bin/expect';
// Location of expect script (see helpers/passwd-expect)
$config['password_expect_script'] = '';
// Arguments for the expect script. See the helpers/passwd-expect file for details.
// This is probably a good starting default:
// -telent -host localhost -output /tmp/passwd.log -log /tmp/passwd.log
$config['password_expect_params'] = '';
// smb Driver options
// ---------------------
// Samba host (default: localhost)
// Supported replacement variables:
// %n - hostname ($_SERVER['SERVER_NAME'])
// %t - hostname without the first part
// %d - domain (http hostname $_SERVER['HTTP_HOST'] without the first part)
$config['password_smb_host'] = 'localhost';
// Location of smbpasswd binary
$config['password_smb_cmd'] = '/usr/bin/smbpasswd';
// gearman driver options
// ---------------------
// Gearman host (default: localhost)
$config['password_gearman_host'] = 'localhost';
-
// Plesk/PPA Driver options
// --------------------
// You need to allow RCP for IP of roundcube-server in Plesk/PPA Panel
// Plesk RCP Host
$config['password_plesk_host'] = '10.0.0.5';
// Plesk RPC Username
$config['password_plesk_user'] = 'admin';
// Plesk RPC Password
$config['password_plesk_pass'] = 'password';
// Plesk RPC Port
$config['password_plesk_rpc_port'] = '8443';
// Plesk RPC Path
$config['password_plesk_rpc_path'] = 'enterprise/control/agent.php';
// kasswd Driver options
// ---------------------
// Command to use
$config['password_kpasswd_cmd'] = '/usr/bin/kpasswd';
diff --git a/plugins/password/drivers/ldap.php b/plugins/password/drivers/ldap.php
index 6ed5ada04..46c783587 100644
--- a/plugins/password/drivers/ldap.php
+++ b/plugins/password/drivers/ldap.php
@@ -1,381 +1,221 @@
<?php
/**
* LDAP Password Driver
*
* Driver for passwords stored in LDAP
* This driver use the PEAR Net_LDAP2 class (http://pear.php.net/package/Net_LDAP2).
*
* @version 2.0
* @author Edouard MOREAU <edouard.moreau@ensma.fr>
*
* method hashPassword based on code from the phpLDAPadmin development team (http://phpldapadmin.sourceforge.net/).
* method randomSalt based on code from the phpLDAPadmin development team (http://phpldapadmin.sourceforge.net/).
*
* Copyright (C) 2005-2014, The Roundcube Dev Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
class rcube_ldap_password
{
public function save($curpass, $passwd)
{
$rcmail = rcmail::get_instance();
require_once 'Net/LDAP2.php';
// Building user DN
if ($userDN = $rcmail->config->get('password_ldap_userDN_mask')) {
$userDN = self::substitute_vars($userDN);
}
else {
$userDN = $this->search_userdn($rcmail);
}
if (empty($userDN)) {
return PASSWORD_CONNECT_ERROR;
}
// Connection Method
switch($rcmail->config->get('password_ldap_method')) {
case 'admin':
$binddn = $rcmail->config->get('password_ldap_adminDN');
$bindpw = $rcmail->config->get('password_ldap_adminPW');
break;
case 'user':
default:
$binddn = $userDN;
$bindpw = $curpass;
break;
}
// Configuration array
$ldapConfig = array (
'binddn' => $binddn,
'bindpw' => $bindpw,
'basedn' => $rcmail->config->get('password_ldap_basedn'),
'host' => $rcmail->config->get('password_ldap_host'),
'port' => $rcmail->config->get('password_ldap_port'),
'starttls' => $rcmail->config->get('password_ldap_starttls'),
'version' => $rcmail->config->get('password_ldap_version'),
);
// Connecting using the configuration array
$ldap = Net_LDAP2::connect($ldapConfig);
// Checking for connection error
if (is_a($ldap, 'PEAR_Error')) {
return PASSWORD_CONNECT_ERROR;
}
$force = $rcmail->config->get('password_ldap_force_replace');
$pwattr = $rcmail->config->get('password_ldap_pwattr');
$lchattr = $rcmail->config->get('password_ldap_lchattr');
$smbpwattr = $rcmail->config->get('password_ldap_samba_pwattr');
$smblchattr = $rcmail->config->get('password_ldap_samba_lchattr');
$samba = $rcmail->config->get('password_ldap_samba');
$encodage = $rcmail->config->get('password_ldap_encodage');
// Support multiple userPassword values where desired.
// multiple encodings can be specified separated by '+' (e.g. "cram-md5+ssha")
$encodages = explode('+', $encodage);
$crypted_pass = array();
foreach ($encodages as $enc) {
- $cpw = self::hash_password($passwd, $enc);
- if (!empty($cpw)) {
+ if ($cpw = password::hash_password($passwd, $enc)) {
$crypted_pass[] = $cpw;
}
}
// Support password_ldap_samba option for backward compat.
if ($samba && !$smbpwattr) {
$smbpwattr = 'sambaNTPassword';
$smblchattr = 'sambaPwdLastSet';
}
// Crypt new password
if (empty($crypted_pass)) {
return PASSWORD_CRYPT_ERROR;
}
// Crypt new samba password
- if ($smbpwattr && !($samba_pass = self::hash_password($passwd, 'samba'))) {
+ if ($smbpwattr && !($samba_pass = password::hash_password($passwd, 'samba'))) {
return PASSWORD_CRYPT_ERROR;
}
// Writing new crypted password to LDAP
$userEntry = $ldap->getEntry($userDN);
if (Net_LDAP2::isError($userEntry)) {
return PASSWORD_CONNECT_ERROR;
}
if (!$userEntry->replace(array($pwattr => $crypted_pass), $force)) {
return PASSWORD_CONNECT_ERROR;
}
// Updating PasswordLastChange Attribute if desired
if ($lchattr) {
$current_day = (int)(time() / 86400);
if (!$userEntry->replace(array($lchattr => $current_day), $force)) {
return PASSWORD_CONNECT_ERROR;
}
}
// Update Samba password and last change fields
if ($smbpwattr) {
$userEntry->replace(array($smbpwattr => $samba_pass), $force);
}
// Update Samba password last change field
if ($smblchattr) {
$userEntry->replace(array($smblchattr => time()), $force);
}
if (Net_LDAP2::isError($userEntry->update())) {
return PASSWORD_CONNECT_ERROR;
}
// All done, no error
return PASSWORD_SUCCESS;
}
/**
* Bind with searchDN and searchPW and search for the user's DN.
* Use search_base and search_filter defined in config file.
* Return the found DN.
*/
function search_userdn($rcmail)
{
$binddn = $rcmail->config->get('password_ldap_searchDN');
$bindpw = $rcmail->config->get('password_ldap_searchPW');
$ldapConfig = array (
'basedn' => $rcmail->config->get('password_ldap_basedn'),
'host' => $rcmail->config->get('password_ldap_host'),
'port' => $rcmail->config->get('password_ldap_port'),
'starttls' => $rcmail->config->get('password_ldap_starttls'),
'version' => $rcmail->config->get('password_ldap_version'),
);
// allow anonymous searches
if (!empty($binddn)) {
$ldapConfig['binddn'] = $binddn;
$ldapConfig['bindpw'] = $bindpw;
}
$ldap = Net_LDAP2::connect($ldapConfig);
if (is_a($ldap, 'PEAR_Error')) {
return '';
}
$base = self::substitute_vars($rcmail->config->get('password_ldap_search_base'));
$filter = self::substitute_vars($rcmail->config->get('password_ldap_search_filter'));
$options = array (
'scope' => 'sub',
'attributes' => array(),
);
$result = $ldap->search($base, $filter, $options);
$ldap->done();
if (is_a($result, 'PEAR_Error') || ($result->count() != 1)) {
return '';
}
return $result->current()->dn();
}
/**
* Substitute %login, %name, %domain, %dc in $str
* See plugin config for details
*/
static function substitute_vars($str)
{
$str = str_replace('%login', $_SESSION['username'], $str);
$str = str_replace('%l', $_SESSION['username'], $str);
$parts = explode('@', $_SESSION['username']);
if (count($parts) == 2) {
$dc = 'dc='.strtr($parts[1], array('.' => ',dc=')); // hierarchal domain string
$str = str_replace('%name', $parts[0], $str);
$str = str_replace('%n', $parts[0], $str);
$str = str_replace('%dc', $dc, $str);
$str = str_replace('%domain', $parts[1], $str);
$str = str_replace('%d', $parts[1], $str);
}
return $str;
}
-
- /**
- * Code originaly from the phpLDAPadmin development team
- * http://phpldapadmin.sourceforge.net/
- *
- * Hashes a password and returns the hash based on the specified enc_type
- */
- static function hash_password($password_clear, $encodage_type)
- {
- $encodage_type = strtolower($encodage_type);
- switch ($encodage_type) {
- case 'crypt':
- $crypted_password = '{CRYPT}' . crypt($password_clear, self::random_salt(2));
- break;
-
- case 'ext_des':
- /* Extended DES crypt. see OpenBSD crypt man page */
- if (!defined('CRYPT_EXT_DES') || CRYPT_EXT_DES == 0) {
- /* Your system crypt library does not support extended DES encryption */
- return false;
- }
-
- $crypted_password = '{CRYPT}' . crypt($password_clear, '_' . self::random_salt(8));
- break;
-
- case 'md5crypt':
- if (!defined('CRYPT_MD5') || CRYPT_MD5 == 0) {
- /* Your system crypt library does not support md5crypt encryption */
- return false;
- }
-
- $crypted_password = '{CRYPT}' . crypt($password_clear, '$1$' . self::random_salt(9));
- break;
-
- case 'blowfish':
- if (!defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH == 0) {
- /* Your system crypt library does not support blowfish encryption */
- return false;
- }
-
- $rcmail = rcmail::get_instance();
- $cost = (int) $rcmail->config->get('password_blowfish_cost');
- $cost = $cost < 4 || $cost > 31 ? 12 : $cost;
- $prefix = sprintf('$2a$%02d$', $cost);
-
- $crypted_password = '{CRYPT}' . crypt($password_clear, $prefix . self::random_salt(22));
- break;
-
- case 'md5':
- $crypted_password = '{MD5}' . base64_encode(pack('H*', md5($password_clear)));
- break;
-
- case 'sha':
- if (function_exists('sha1')) {
- /* Use PHP 4.3.0+ sha1 function, if it is available */
- $crypted_password = '{SHA}' . base64_encode(pack('H*', sha1($password_clear)));
- }
- else if (function_exists('hash')) {
- $crypted_password = '{SHA}' . base64_encode(hash('sha1', $password_clear, true));
- }
- else if (function_exists('mhash')) {
- $crypted_password = '{SHA}' . base64_encode(mhash(MHASH_SHA1, $password_clear));
- }
- else {
- /* Your PHP install does not have the mhash()/hash() nor sha1() function */
- return false;
- }
- break;
-
- case 'ssha':
- $salt = substr(pack('h*', md5(mt_rand())), 0, 8);
-
- if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
- $salt = mhash_keygen_s2k(MHASH_SHA1, $password_clear, $salt, 4);
- $password = mhash(MHASH_SHA1, $password_clear . $salt);
- }
- else if (function_exists('sha1')) {
- $salt = substr(pack("H*", sha1($salt . $password_clear)), 0, 4);
- $password = sha1($password_clear . $salt, true);
- }
- else if (function_exists('hash')) {
- $salt = substr(pack("H*", hash('sha1', $salt . $password_clear)), 0, 4);
- $password = hash('sha1', $password_clear . $salt, true);
- }
-
- if ($password) {
- $crypted_password = '{SSHA}' . base64_encode($password . $salt);
- }
- else {
- /* Your PHP install does not have the mhash()/hash() nor sha1() function */
- return false;
- }
- break;
-
-
- case 'smd5':
- $salt = substr(pack('h*', md5(mt_rand())), 0, 8);
-
- if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
- $salt = mhash_keygen_s2k(MHASH_MD5, $password_clear, $salt, 4);
- $password = mhash(MHASH_MD5, $password_clear . $salt);
- }
- else if (function_exists('hash')) {
- $salt = substr(pack("H*", hash('md5', $salt . $password_clear)), 0, 4);
- $password = hash('md5', $password_clear . $salt, true);
- }
- else {
- $salt = substr(pack("H*", md5($salt . $password_clear)), 0, 4);
- $password = md5($password_clear . $salt, true);
- }
-
- $crypted_password = '{SMD5}' . base64_encode($password . $salt);
- break;
-
- case 'samba':
- if (function_exists('hash')) {
- $crypted_password = hash('md4', rcube_charset::convert($password_clear, RCUBE_CHARSET, 'UTF-16LE'));
- $crypted_password = strtoupper($crypted_password);
- }
- else {
- /* Your PHP install does not have the hash() function */
- return false;
- }
- break;
-
- case 'ad':
- $crypted_password = rcube_charset::convert('"' . $password_clear . '"', RCUBE_CHARSET, 'UTF-16LE');
- break;
-
- case 'cram-md5':
- require_once __DIR__ . '/../helpers/dovecot_hmacmd5.php';
- return dovecot_hmacmd5($password_clear);
- break;
-
- case 'clear':
- default:
- $crypted_password = $password_clear;
- }
-
- return $crypted_password;
- }
-
- /**
- * Code originaly from the phpLDAPadmin development team
- * http://phpldapadmin.sourceforge.net/
- *
- * Used to generate a random salt for crypt-style passwords
- */
- static function random_salt($length)
- {
- $possible = '0123456789' . 'abcdefghijklmnopqrstuvwxyz' . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . './';
- $str = '';
-
- while (strlen($str) < $length) {
- $str .= substr($possible, (rand() % strlen($possible)), 1);
- }
-
- return $str;
- }
}
diff --git a/plugins/password/drivers/ldap_simple.php b/plugins/password/drivers/ldap_simple.php
index 9123ea81f..5b8220577 100644
--- a/plugins/password/drivers/ldap_simple.php
+++ b/plugins/password/drivers/ldap_simple.php
@@ -1,238 +1,238 @@
<?php
/**
* Simple LDAP Password Driver
*
* Driver for passwords stored in LDAP
* This driver is based on Edouard's LDAP Password Driver, but does not
* require PEAR's Net_LDAP2 to be installed
*
* @version 2.0
* @author Wout Decre <wout@canodus.be>
* @author Aleksander Machniak <machniak@kolabsys.com>
*
* Copyright (C) 2005-2014, The Roundcube Dev Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
class rcube_ldap_simple_password
{
private $debug = false;
function save($curpass, $passwd)
{
$rcmail = rcmail::get_instance();
$this->debug = $rcmail->config->get('ldap_debug');
$ldap_host = $rcmail->config->get('password_ldap_host');
$ldap_port = $rcmail->config->get('password_ldap_port');
$this->_debug("C: Connect to $ldap_host:$ldap_port");
// Connect
if (!$ds = ldap_connect($ldap_host, $ldap_port)) {
$this->_debug("S: NOT OK");
rcube::raise_error(array(
'code' => 100, 'type' => 'ldap',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Could not connect to LDAP server"
),
true);
return PASSWORD_CONNECT_ERROR;
}
$this->_debug("S: OK");
// Set protocol version
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $rcmail->config->get('password_ldap_version'));
// Start TLS
if ($rcmail->config->get('password_ldap_starttls')) {
if (!ldap_start_tls($ds)) {
ldap_unbind($ds);
return PASSWORD_CONNECT_ERROR;
}
}
// include 'ldap' driver, we share some static methods with it
require_once INSTALL_PATH . 'plugins/password/drivers/ldap.php';
// other plugins might want to modify user DN
$plugin = $rcmail->plugins->exec_hook('password_ldap_bind', array(
'user_dn' => '', 'conn' => $ds));
// Build user DN
if (!empty($plugin['user_dn'])) {
$user_dn = $plugin['user_dn'];
}
else if ($user_dn = $rcmail->config->get('password_ldap_userDN_mask')) {
$user_dn = rcube_ldap_password::substitute_vars($user_dn);
}
else {
$user_dn = $this->search_userdn($rcmail, $ds);
}
if (empty($user_dn)) {
ldap_unbind($ds);
return PASSWORD_CONNECT_ERROR;
}
// Connection method
switch ($rcmail->config->get('password_ldap_method')) {
case 'admin':
$binddn = $rcmail->config->get('password_ldap_adminDN');
$bindpw = $rcmail->config->get('password_ldap_adminPW');
break;
case 'user':
default:
$binddn = $user_dn;
$bindpw = $curpass;
break;
}
$lchattr = $rcmail->config->get('password_ldap_lchattr');
$pwattr = $rcmail->config->get('password_ldap_pwattr');
$smbpwattr = $rcmail->config->get('password_ldap_samba_pwattr');
$smblchattr = $rcmail->config->get('password_ldap_samba_lchattr');
$samba = $rcmail->config->get('password_ldap_samba');
$pass_mode = $rcmail->config->get('password_ldap_encodage');
- $crypted_pass = rcube_ldap_password::hash_password($passwd, $pass_mode);
+ $crypted_pass = password::hash_password($passwd, $pass_mode);
// Support password_ldap_samba option for backward compat.
if ($samba && !$smbpwattr) {
$smbpwattr = 'sambaNTPassword';
$smblchattr = 'sambaPwdLastSet';
}
// Crypt new password
if (!$crypted_pass) {
return PASSWORD_CRYPT_ERROR;
}
// Crypt new Samba password
- if ($smbpwattr && !($samba_pass = rcube_ldap_password::hash_password($passwd, 'samba'))) {
+ if ($smbpwattr && !($samba_pass = password::hash_password($passwd, 'samba'))) {
return PASSWORD_CRYPT_ERROR;
}
$this->_debug("C: Bind $binddn, pass: **** [" . strlen($bindpw) . "]");
// Bind
if (!ldap_bind($ds, $binddn, $bindpw)) {
$this->_debug("S: ".ldap_error($ds));
ldap_unbind($ds);
return PASSWORD_CONNECT_ERROR;
}
$this->_debug("S: OK");
$entry[$pwattr] = $crypted_pass;
// Update PasswordLastChange Attribute if desired
if ($lchattr) {
$entry[$lchattr] = (int)(time() / 86400);
}
// Update Samba password
if ($smbpwattr) {
$entry[$smbpwattr] = $samba_pass;
}
// Update Samba password last change
if ($smblchattr) {
$entry[$smblchattr] = time();
}
$this->_debug("C: Modify $user_dn: " . print_r($entry, true));
if (!ldap_modify($ds, $user_dn, $entry)) {
$this->_debug("S: ".ldap_error($ds));
ldap_unbind($ds);
return PASSWORD_CONNECT_ERROR;
}
$this->_debug("S: OK");
// All done, no error
ldap_unbind($ds);
return PASSWORD_SUCCESS;
}
/**
* Bind with searchDN and searchPW and search for the user's DN
* Use search_base and search_filter defined in config file
* Return the found DN
*/
function search_userdn($rcmail, $ds)
{
$search_user = $rcmail->config->get('password_ldap_searchDN');
$search_pass = $rcmail->config->get('password_ldap_searchPW');
$search_base = $rcmail->config->get('password_ldap_search_base');
$search_filter = $rcmail->config->get('password_ldap_search_filter');
if (empty($search_filter)) {
return false;
}
$this->_debug("C: Bind " . ($search_user ? $search_user : '[anonymous]'));
// Bind
if (!ldap_bind($ds, $search_user, $search_pass)) {
$this->_debug("S: ".ldap_error($ds));
return false;
}
$this->_debug("S: OK");
$search_base = rcube_ldap_password::substitute_vars($search_base);
$search_filter = rcube_ldap_password::substitute_vars($search_filter);
$this->_debug("C: Search $search_base for $search_filter");
// Search for the DN
if (!$sr = ldap_search($ds, $search_base, $search_filter)) {
$this->_debug("S: ".ldap_error($ds));
return false;
}
$found = ldap_count_entries($ds, $sr);
$this->_debug("S: OK [found $found records]");
// If no or more entries were found, return false
if ($found != 1) {
return false;
}
return ldap_get_dn($ds, ldap_first_entry($ds, $sr));
}
/**
* Prints debug info to the log
*/
private function _debug($str)
{
if ($this->debug) {
rcube::write_log('ldap', $str);
}
}
}
diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php
index 37e162e22..9659fa0e0 100644
--- a/plugins/password/drivers/sql.php
+++ b/plugins/password/drivers/sql.php
@@ -1,212 +1,172 @@
<?php
/**
* SQL Password Driver
*
* Driver for passwords stored in SQL database
*
* @version 2.0
* @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl>
*
* Copyright (C) 2005-2013, The Roundcube Dev Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
class rcube_sql_password
{
function save($curpass, $passwd)
{
$rcmail = rcmail::get_instance();
if (!($sql = $rcmail->config->get('password_query'))) {
$sql = 'SELECT update_passwd(%c, %u)';
}
if ($dsn = $rcmail->config->get('password_db_dsn')) {
$db = rcube_db::factory($dsn, '', false);
$db->set_debug((bool)$rcmail->config->get('sql_debug'));
}
else {
$db = $rcmail->get_dbh();
}
if ($db->is_error()) {
return PASSWORD_ERROR;
}
- // crypted password
- if (strpos($sql, '%c') !== FALSE) {
- $salt = '';
-
- if (!($crypt_hash = $rcmail->config->get('password_crypt_hash'))) {
- if (CRYPT_MD5)
- $crypt_hash = 'md5';
- else if (CRYPT_STD_DES)
- $crypt_hash = 'des';
- }
+ // new password - default hash method
+ if (strpos($sql, '%P') !== false) {
+ $password = password::hash_password($passwd);
- switch ($crypt_hash) {
- case 'md5':
- $len = 8;
- $salt_hashindicator = '$1$';
- break;
- case 'des':
- $len = 2;
- break;
- case 'blowfish':
- $cost = (int) $rcmail->config->get('password_blowfish_cost');
- $cost = $cost < 4 || $cost > 31 ? 12 : $cost;
- $len = 22;
- $salt_hashindicator = sprintf('$2a$%02d$', $cost);
- break;
- case 'sha256':
- $len = 16;
- $salt_hashindicator = '$5$';
- break;
- case 'sha512':
- $len = 16;
- $salt_hashindicator = '$6$';
- break;
- default:
+ if ($password === false) {
return PASSWORD_CRYPT_ERROR;
}
- //Restrict the character set used as salt (#1488136)
- $seedchars = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
- for ($i = 0; $i < $len ; $i++) {
- $salt .= $seedchars[rand(0, 63)];
+ $sql = str_replace('%P', $db->quote($password), $sql);
+ }
+
+ // old password - default hash method
+ if (strpos($sql, '%O') !== false) {
+ $password = password::hash_password($curpass);
+
+ if ($password === false) {
+ return PASSWORD_CRYPT_ERROR;
}
- $sql = str_replace('%c', $db->quote(crypt($passwd, $salt_hashindicator ? $salt_hashindicator .$salt.'$' : $salt)), $sql);
+ $sql = str_replace('%O', $db->quote($password), $sql);
}
- // dovecotpw
- if (strpos($sql, '%D') !== FALSE) {
- if (!($dovecotpw = $rcmail->config->get('password_dovecotpw')))
- $dovecotpw = 'dovecotpw';
- if (!($method = $rcmail->config->get('password_dovecotpw_method')))
- $method = 'CRAM-MD5';
+ // crypted password (deprecated, use %P)
+ if (strpos($sql, '%c') !== false) {
+ $password = password::hash_password($passwd, 'crypt', false);
- // use common temp dir
- $tmp_dir = $rcmail->config->get('temp_dir');
- $tmpfile = tempnam($tmp_dir, 'roundcube-');
-
- $pipe = popen("$dovecotpw -s '$method' > '$tmpfile'", "w");
- if (!$pipe) {
- unlink($tmpfile);
+ if ($password === false) {
return PASSWORD_CRYPT_ERROR;
}
- else {
- fwrite($pipe, $passwd . "\n", 1+strlen($passwd)); usleep(1000);
- fwrite($pipe, $passwd . "\n", 1+strlen($passwd));
- pclose($pipe);
- $newpass = trim(file_get_contents($tmpfile), "\n");
- if (!preg_match('/^\{' . $method . '\}/', $newpass)) {
- return PASSWORD_CRYPT_ERROR;
- }
- if (!$rcmail->config->get('password_dovecotpw_with_method'))
- $newpass = trim(str_replace('{' . $method . '}', '', $newpass));
- unlink($tmpfile);
- }
- $sql = str_replace('%D', $db->quote($newpass), $sql);
+
+ $sql = str_replace('%c', $db->quote($password), $sql);
}
- // hashed passwords
- if (preg_match('/%[n|q]/', $sql)) {
- if (!extension_loaded('hash')) {
- rcube::raise_error(array(
- 'code' => 600,
- 'type' => 'php',
- 'file' => __FILE__, 'line' => __LINE__,
- 'message' => "Password plugin: 'hash' extension not loaded!"
- ), true, false);
-
- return PASSWORD_ERROR;
+ // dovecotpw (deprecated, use %P)
+ if (strpos($sql, '%D') !== false) {
+ $password = password::hash_password($passwd, 'dovecot', false);
+
+ if ($password === false) {
+ return PASSWORD_CRYPT_ERROR;
}
- if (!($hash_algo = strtolower($rcmail->config->get('password_hash_algorithm')))) {
- $hash_algo = 'sha1';
+ $sql = str_replace('%D', $db->quote($password), $sql);
+ }
+
+ // hashed passwords (deprecated, use %P)
+ if (strpos($sql, '%n') !== false) {
+ $password = password::hash_password($passwd, 'hash', false);
+
+ if ($password === false) {
+ return PASSWORD_CRYPT_ERROR;
}
- $hash_passwd = hash($hash_algo, $passwd);
- $hash_curpass = hash($hash_algo, $curpass);
+ $sql = str_replace('%n', $db->quote($password, 'text'), $sql);
+ }
+
+ // hashed passwords (deprecated, use %P)
+ if (strpos($sql, '%q') !== false) {
+ $password = password::hash_password($curpass, 'hash', false);
- if ($rcmail->config->get('password_hash_base64')) {
- $hash_passwd = base64_encode(pack('H*', $hash_passwd));
- $hash_curpass = base64_encode(pack('H*', $hash_curpass));
+ if ($password === false) {
+ return PASSWORD_CRYPT_ERROR;
}
- $sql = str_replace('%n', $db->quote($hash_passwd, 'text'), $sql);
- $sql = str_replace('%q', $db->quote($hash_curpass, 'text'), $sql);
+ $sql = str_replace('%q', $db->quote($password, 'text'), $sql);
}
// Handle clear text passwords securely (#1487034)
$sql_vars = array();
if (preg_match_all('/%[p|o]/', $sql, $m)) {
foreach ($m[0] as $var) {
if ($var == '%p') {
$sql = preg_replace('/%p/', '?', $sql, 1);
$sql_vars[] = (string) $passwd;
}
else { // %o
$sql = preg_replace('/%o/', '?', $sql, 1);
$sql_vars[] = (string) $curpass;
}
}
}
$local_part = $rcmail->user->get_username('local');
$domain_part = $rcmail->user->get_username('domain');
$username = $_SESSION['username'];
$host = $_SESSION['imap_host'];
// convert domains to/from punnycode
if ($rcmail->config->get('password_idn_ascii')) {
$domain_part = rcube_utils::idn_to_ascii($domain_part);
$username = rcube_utils::idn_to_ascii($username);
$host = rcube_utils::idn_to_ascii($host);
}
else {
$domain_part = rcube_utils::idn_to_utf8($domain_part);
$username = rcube_utils::idn_to_utf8($username);
$host = rcube_utils::idn_to_utf8($host);
}
// at least we should always have the local part
$sql = str_replace('%l', $db->quote($local_part, 'text'), $sql);
$sql = str_replace('%d', $db->quote($domain_part, 'text'), $sql);
$sql = str_replace('%u', $db->quote($username, 'text'), $sql);
$sql = str_replace('%h', $db->quote($host, 'text'), $sql);
$res = $db->query($sql, $sql_vars);
if (!$db->is_error()) {
if (strtolower(substr(trim($sql),0,6)) == 'select') {
if ($db->fetch_array($res)) {
return PASSWORD_SUCCESS;
}
}
else {
// This is the good case: 1 row updated
if ($db->affected_rows($res) == 1)
return PASSWORD_SUCCESS;
// @TODO: Some queries don't affect any rows
// Should we assume a success if there was no error?
}
}
return PASSWORD_ERROR;
}
}
diff --git a/plugins/password/helpers/dovecot_hmacmd5.php b/plugins/password/helpers/dovecot_hmacmd5.php
index 644b5377e..da4d005f7 100644
--- a/plugins/password/helpers/dovecot_hmacmd5.php
+++ b/plugins/password/helpers/dovecot_hmacmd5.php
@@ -1,191 +1,191 @@
<?php
/**
*
* dovecot_hmacmd5.php V1.01
*
* Generates HMAC-MD5 'contexts' for Dovecot's password files.
*
* (C) 2008 Hajo Noerenberg
*
* http://www.noerenberg.de/hajo/pub/dovecot_hmacmd5.php.txt
*
* Most of the code has been shamelessly stolen from various sources:
*
* (C) Paul Johnston 1999 - 2000 / http://pajhome.org.uk/crypt/md5/
* (C) William K. Cole 2008 / http://www.scconsult.com/bill/crampass.pl
* (C) Borfast 2002 / http://www.zend.com/code/codex.php?ozid=962&single=1
* (C) Thomas Weber / http://pajhome.org.uk/crypt/md5/contrib/md5.java.txt
*
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 3.0 as
* published by the Free Software Foundation.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/gpl-3.0.txt>.
*
*/
/* Convert a 32-bit number to a hex string with ls-byte first
*/
function rhex($n) {
$hex_chr = "0123456789abcdef"; $r = '';
for($j = 0; $j <= 3; $j++)
$r .= $hex_chr[($n >> ($j * 8 + 4)) & 0x0F] . $hex_chr[($n >> ($j * 8)) & 0x0F];
return $r;
}
/* zeroFill() is needed because PHP doesn't have a zero-fill
* right shift operator like JavaScript's >>>
*/
function zeroFill($a, $b) {
$z = hexdec(80000000);
if ($z & $a) {
$a >>= 1;
$a &= (~$z);
$a |= 0x40000000;
$a >>= ($b-1);
} else {
$a >>= $b;
}
return $a;
}
/* Bitwise rotate a 32-bit number to the left
*/
function bit_rol($num, $cnt) {
return ($num << $cnt) | (zeroFill($num, (32 - $cnt)));
}
/* Add integers, wrapping at 2^32
*/
function safe_add($x, $y) {
return (($x&0x7FFFFFFF) + ($y&0x7FFFFFFF)) ^ ($x&0x80000000) ^ ($y&0x80000000);
}
/* These functions implement the four basic operations the algorithm uses.
*/
function md5_cmn($q, $a, $b, $x, $s, $t) {
return safe_add(bit_rol(safe_add(safe_add($a, $q), safe_add($x, $t)), $s), $b);
}
function md5_ff($a, $b, $c, $d, $x, $s, $t) {
return md5_cmn(($b & $c) | ((~$b) & $d), $a, $b, $x, $s, $t);
}
function md5_gg($a, $b, $c, $d, $x, $s, $t) {
return md5_cmn(($b & $d) | ($c & (~$d)), $a, $b, $x, $s, $t);
}
function md5_hh($a, $b, $c, $d, $x, $s, $t) {
return md5_cmn($b ^ $c ^ $d, $a, $b, $x, $s, $t);
}
function md5_ii($a, $b, $c, $d, $x, $s, $t) {
return md5_cmn($c ^ ($b | (~$d)), $a, $b, $x, $s, $t);
}
/* Calculate the first round of the MD5 algorithm
*/
function md5_oneround($s, $io) {
$s = str_pad($s, 64, chr(0x00));
$x = array_fill(0, 16, 0);
for($i = 0; $i < 64; $i++)
$x[$i >> 2] |= (($io ? 0x36 : 0x5c) ^ ord($s[$i])) << (($i % 4) * 8);
$a = $olda = 1732584193;
$b = $oldb = -271733879;
$c = $oldc = -1732584194;
$d = $oldd = 271733878;
$a = md5_ff($a, $b, $c, $d, $x[ 0], 7 , -680876936);
$d = md5_ff($d, $a, $b, $c, $x[ 1], 12, -389564586);
$c = md5_ff($c, $d, $a, $b, $x[ 2], 17, 606105819);
$b = md5_ff($b, $c, $d, $a, $x[ 3], 22, -1044525330);
$a = md5_ff($a, $b, $c, $d, $x[ 4], 7 , -176418897);
$d = md5_ff($d, $a, $b, $c, $x[ 5], 12, 1200080426);
$c = md5_ff($c, $d, $a, $b, $x[ 6], 17, -1473231341);
$b = md5_ff($b, $c, $d, $a, $x[ 7], 22, -45705983);
$a = md5_ff($a, $b, $c, $d, $x[ 8], 7 , 1770035416);
$d = md5_ff($d, $a, $b, $c, $x[ 9], 12, -1958414417);
$c = md5_ff($c, $d, $a, $b, $x[10], 17, -42063);
$b = md5_ff($b, $c, $d, $a, $x[11], 22, -1990404162);
$a = md5_ff($a, $b, $c, $d, $x[12], 7 , 1804603682);
$d = md5_ff($d, $a, $b, $c, $x[13], 12, -40341101);
$c = md5_ff($c, $d, $a, $b, $x[14], 17, -1502002290);
$b = md5_ff($b, $c, $d, $a, $x[15], 22, 1236535329);
$a = md5_gg($a, $b, $c, $d, $x[ 1], 5 , -165796510);
$d = md5_gg($d, $a, $b, $c, $x[ 6], 9 , -1069501632);
$c = md5_gg($c, $d, $a, $b, $x[11], 14, 643717713);
$b = md5_gg($b, $c, $d, $a, $x[ 0], 20, -373897302);
$a = md5_gg($a, $b, $c, $d, $x[ 5], 5 , -701558691);
$d = md5_gg($d, $a, $b, $c, $x[10], 9 , 38016083);
$c = md5_gg($c, $d, $a, $b, $x[15], 14, -660478335);
$b = md5_gg($b, $c, $d, $a, $x[ 4], 20, -405537848);
$a = md5_gg($a, $b, $c, $d, $x[ 9], 5 , 568446438);
$d = md5_gg($d, $a, $b, $c, $x[14], 9 , -1019803690);
$c = md5_gg($c, $d, $a, $b, $x[ 3], 14, -187363961);
$b = md5_gg($b, $c, $d, $a, $x[ 8], 20, 1163531501);
$a = md5_gg($a, $b, $c, $d, $x[13], 5 , -1444681467);
$d = md5_gg($d, $a, $b, $c, $x[ 2], 9 , -51403784);
$c = md5_gg($c, $d, $a, $b, $x[ 7], 14, 1735328473);
$b = md5_gg($b, $c, $d, $a, $x[12], 20, -1926607734);
$a = md5_hh($a, $b, $c, $d, $x[ 5], 4 , -378558);
$d = md5_hh($d, $a, $b, $c, $x[ 8], 11, -2022574463);
$c = md5_hh($c, $d, $a, $b, $x[11], 16, 1839030562);
$b = md5_hh($b, $c, $d, $a, $x[14], 23, -35309556);
$a = md5_hh($a, $b, $c, $d, $x[ 1], 4 , -1530992060);
$d = md5_hh($d, $a, $b, $c, $x[ 4], 11, 1272893353);
$c = md5_hh($c, $d, $a, $b, $x[ 7], 16, -155497632);
$b = md5_hh($b, $c, $d, $a, $x[10], 23, -1094730640);
$a = md5_hh($a, $b, $c, $d, $x[13], 4 , 681279174);
$d = md5_hh($d, $a, $b, $c, $x[ 0], 11, -358537222);
$c = md5_hh($c, $d, $a, $b, $x[ 3], 16, -722521979);
$b = md5_hh($b, $c, $d, $a, $x[ 6], 23, 76029189);
$a = md5_hh($a, $b, $c, $d, $x[ 9], 4 , -640364487);
$d = md5_hh($d, $a, $b, $c, $x[12], 11, -421815835);
$c = md5_hh($c, $d, $a, $b, $x[15], 16, 530742520);
$b = md5_hh($b, $c, $d, $a, $x[ 2], 23, -995338651);
$a = md5_ii($a, $b, $c, $d, $x[ 0], 6 , -198630844);
$d = md5_ii($d, $a, $b, $c, $x[ 7], 10, 1126891415);
$c = md5_ii($c, $d, $a, $b, $x[14], 15, -1416354905);
$b = md5_ii($b, $c, $d, $a, $x[ 5], 21, -57434055);
$a = md5_ii($a, $b, $c, $d, $x[12], 6 , 1700485571);
$d = md5_ii($d, $a, $b, $c, $x[ 3], 10, -1894986606);
$c = md5_ii($c, $d, $a, $b, $x[10], 15, -1051523);
$b = md5_ii($b, $c, $d, $a, $x[ 1], 21, -2054922799);
$a = md5_ii($a, $b, $c, $d, $x[ 8], 6 , 1873313359);
$d = md5_ii($d, $a, $b, $c, $x[15], 10, -30611744);
$c = md5_ii($c, $d, $a, $b, $x[ 6], 15, -1560198380);
$b = md5_ii($b, $c, $d, $a, $x[13], 21, 1309151649);
$a = md5_ii($a, $b, $c, $d, $x[ 4], 6 , -145523070);
$d = md5_ii($d, $a, $b, $c, $x[11], 10, -1120210379);
$c = md5_ii($c, $d, $a, $b, $x[ 2], 15, 718787259);
$b = md5_ii($b, $c, $d, $a, $x[ 9], 21, -343485551);
$a = safe_add($a, $olda);
$b = safe_add($b, $oldb);
$c = safe_add($c, $oldc);
$d = safe_add($d, $oldd);
return rhex($a) . rhex($b) . rhex($c) . rhex($d);
}
function dovecot_hmacmd5 ($s) {
if (strlen($s) > 64) $s=pack("H*", md5($s));
- return "{CRAM-MD5}" . md5_oneround($s, 0) . md5_oneround($s, 1);
+ return md5_oneround($s, 0) . md5_oneround($s, 1);
}
diff --git a/plugins/password/password.php b/plugins/password/password.php
index 9239cd0b0..476e9eac8 100644
--- a/plugins/password/password.php
+++ b/plugins/password/password.php
@@ -1,370 +1,636 @@
<?php
/**
* Password Plugin for Roundcube
*
* @version @package_version@
* @author Aleksander Machniak <alec@alec.pl>
*
* Copyright (C) 2005-2013, The Roundcube Dev Team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
define('PASSWORD_CRYPT_ERROR', 1);
define('PASSWORD_ERROR', 2);
define('PASSWORD_CONNECT_ERROR', 3);
define('PASSWORD_SUCCESS', 0);
/**
* Change password plugin
*
* Plugin that adds functionality to change a users password.
* It provides common functionality and user interface and supports
* several backends to finally update the password.
*
* For installation and configuration instructions please read the README file.
*
* @author Aleksander Machniak
*/
class password extends rcube_plugin
{
public $task = 'settings|login';
public $noframe = true;
public $noajax = true;
private $newuser = false;
function init()
{
$rcmail = rcmail::get_instance();
$this->load_config();
if ($rcmail->task == 'settings') {
if (!$this->check_host_login_exceptions()) {
return;
}
$this->add_texts('localization/');
$this->add_hook('settings_actions', array($this, 'settings_actions'));
$this->register_action('plugin.password', array($this, 'password_init'));
$this->register_action('plugin.password-save', array($this, 'password_save'));
if (strpos($rcmail->action, 'plugin.password') === 0) {
$this->include_script('password.js');
}
}
else if ($rcmail->config->get('password_force_new_user')) {
$this->add_hook('user_create', array($this, 'user_create'));
$this->add_hook('login_after', array($this, 'login_after'));
}
}
function settings_actions($args)
{
// register as settings action
$args['actions'][] = array(
'action' => 'plugin.password',
'class' => 'password',
'label' => 'password',
'title' => 'changepasswd',
'domain' => 'password',
);
return $args;
}
function password_init()
{
$this->register_handler('plugin.body', array($this, 'password_form'));
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($this->gettext('changepasswd'));
if (rcube_utils::get_input_value('_first', rcube_utils::INPUT_GET)) {
$rcmail->output->command('display_message', $this->gettext('firstloginchange'), 'notice');
}
$rcmail->output->send('plugin');
}
function password_save()
{
$this->register_handler('plugin.body', array($this, 'password_form'));
$rcmail = rcmail::get_instance();
$rcmail->output->set_pagetitle($this->gettext('changepasswd'));
$confirm = $rcmail->config->get('password_confirm_current');
$required_length = intval($rcmail->config->get('password_minimum_length'));
$check_strength = $rcmail->config->get('password_require_nonalpha');
if (($confirm && !isset($_POST['_curpasswd'])) || !isset($_POST['_newpasswd'])) {
$rcmail->output->command('display_message', $this->gettext('nopassword'), 'error');
}
else {
$charset = strtoupper($rcmail->config->get('password_charset', 'ISO-8859-1'));
$rc_charset = strtoupper($rcmail->output->get_charset());
$sespwd = $rcmail->decrypt($_SESSION['password']);
$curpwd = $confirm ? rcube_utils::get_input_value('_curpasswd', rcube_utils::INPUT_POST, true, $charset) : $sespwd;
$newpwd = rcube_utils::get_input_value('_newpasswd', rcube_utils::INPUT_POST, true);
$conpwd = rcube_utils::get_input_value('_confpasswd', rcube_utils::INPUT_POST, true);
// check allowed characters according to the configured 'password_charset' option
// by converting the password entered by the user to this charset and back to UTF-8
$orig_pwd = $newpwd;
$chk_pwd = rcube_charset::convert($orig_pwd, $rc_charset, $charset);
$chk_pwd = rcube_charset::convert($chk_pwd, $charset, $rc_charset);
// WARNING: Default password_charset is ISO-8859-1, so conversion will
// change national characters. This may disable possibility of using
// the same password in other MUA's.
// We're doing this for consistence with Roundcube core
$newpwd = rcube_charset::convert($newpwd, $rc_charset, $charset);
$conpwd = rcube_charset::convert($conpwd, $rc_charset, $charset);
if ($chk_pwd != $orig_pwd) {
$rcmail->output->command('display_message', $this->gettext('passwordforbidden'), 'error');
}
// other passwords validity checks
else if ($conpwd != $newpwd) {
$rcmail->output->command('display_message', $this->gettext('passwordinconsistency'), 'error');
}
else if ($confirm && $sespwd != $curpwd) {
$rcmail->output->command('display_message', $this->gettext('passwordincorrect'), 'error');
}
else if ($required_length && strlen($newpwd) < $required_length) {
$rcmail->output->command('display_message', $this->gettext(
array('name' => 'passwordshort', 'vars' => array('length' => $required_length))), 'error');
}
else if ($check_strength && (!preg_match("/[0-9]/", $newpwd) || !preg_match("/[^A-Za-z0-9]/", $newpwd))) {
$rcmail->output->command('display_message', $this->gettext('passwordweak'), 'error');
}
// password is the same as the old one, do nothing, return success
else if ($sespwd == $newpwd && !$rcmail->config->get('password_force_save')) {
$rcmail->output->command('display_message', $this->gettext('successfullysaved'), 'confirmation');
}
// try to save the password
else if (!($res = $this->_save($curpwd, $newpwd))) {
$rcmail->output->command('display_message', $this->gettext('successfullysaved'), 'confirmation');
// allow additional actions after password change (e.g. reset some backends)
$plugin = $rcmail->plugins->exec_hook('password_change', array(
'old_pass' => $curpwd, 'new_pass' => $newpwd));
// Reset session password
$_SESSION['password'] = $rcmail->encrypt($plugin['new_pass']);
// Log password change
if ($rcmail->config->get('password_log')) {
rcube::write_log('password', sprintf('Password changed for user %s (ID: %d) from %s',
$rcmail->get_user_name(), $rcmail->user->ID, rcube_utils::remote_ip()));
}
}
else {
$rcmail->output->command('display_message', $res, 'error');
}
}
$rcmail->overwrite_action('plugin.password');
$rcmail->output->send('plugin');
}
function password_form()
{
$rcmail = rcmail::get_instance();
// add some labels to client
$rcmail->output->add_label(
'password.nopassword',
'password.nocurpassword',
'password.passwordinconsistency'
);
$rcmail->output->set_env('product_name', $rcmail->config->get('product_name'));
$table = new html_table(array('cols' => 2));
if ($rcmail->config->get('password_confirm_current')) {
// show current password selection
$field_id = 'curpasswd';
$input_curpasswd = new html_passwordfield(array('name' => '_curpasswd', 'id' => $field_id,
'size' => 20, 'autocomplete' => 'off'));
$table->add('title', html::label($field_id, rcube::Q($this->gettext('curpasswd'))));
$table->add(null, $input_curpasswd->show());
}
// show new password selection
$field_id = 'newpasswd';
$input_newpasswd = new html_passwordfield(array('name' => '_newpasswd', 'id' => $field_id,
'size' => 20, 'autocomplete' => 'off'));
$table->add('title', html::label($field_id, rcube::Q($this->gettext('newpasswd'))));
$table->add(null, $input_newpasswd->show());
// show confirm password selection
$field_id = 'confpasswd';
$input_confpasswd = new html_passwordfield(array('name' => '_confpasswd', 'id' => $field_id,
'size' => 20, 'autocomplete' => 'off'));
$table->add('title', html::label($field_id, rcube::Q($this->gettext('confpasswd'))));
$table->add(null, $input_confpasswd->show());
$rules = '';
$required_length = intval($rcmail->config->get('password_minimum_length'));
if ($required_length > 0) {
$rules .= html::tag('li', array('id' => 'required-length'), $this->gettext(array(
'name' => 'passwordshort',
'vars' => array('length' => $required_length)
)));
}
if ($rcmail->config->get('password_require_nonalpha')) {
$rules .= html::tag('li', array('id' => 'require-nonalpha'), $this->gettext('passwordweak'));
}
if (!empty($rules)) {
$rules = html::tag('ul', array('id' => 'ruleslist'), $rules);
}
$out = html::div(array('class' => 'box'),
html::div(array('id' => 'prefs-title', 'class' => 'boxtitle'), $this->gettext('changepasswd')) .
html::div(array('class' => 'boxcontent'), $table->show() .
$rules .
html::p(null,
$rcmail->output->button(array(
'command' => 'plugin.password-save',
'type' => 'input',
'class' => 'button mainaction',
'label' => 'save'
)))));
$rcmail->output->add_gui_object('passform', 'password-form');
return $rcmail->output->form_tag(array(
'id' => 'password-form',
'name' => 'password-form',
'method' => 'post',
'action' => './?_task=settings&_action=plugin.password-save',
), $out);
}
private function _save($curpass, $passwd)
{
$config = rcmail::get_instance()->config;
$driver = $config->get('password_driver', 'sql');
$class = "rcube_{$driver}_password";
$file = $this->home . "/drivers/$driver.php";
if (!file_exists($file)) {
rcube::raise_error(array(
'code' => 600,
'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Password plugin: Unable to open driver file ($file)"
), true, false);
return $this->gettext('internalerror');
}
include_once $file;
if (!class_exists($class, false) || !method_exists($class, 'save')) {
rcube::raise_error(array(
'code' => 600,
'type' => 'php',
'file' => __FILE__, 'line' => __LINE__,
'message' => "Password plugin: Broken driver $driver"
), true, false);
return $this->gettext('internalerror');
}
$object = new $class;
$result = $object->save($curpass, $passwd);
if (is_array($result)) {
$message = $result['message'];
$result = $result['code'];
}
switch ($result) {
case PASSWORD_SUCCESS:
return;
case PASSWORD_CRYPT_ERROR:
$reason = $this->gettext('crypterror');
break;
case PASSWORD_CONNECT_ERROR:
$reason = $this->gettext('connecterror');
break;
case PASSWORD_ERROR:
default:
$reason = $this->gettext('internalerror');
}
if ($message) {
$reason .= ' ' . $message;
}
return $reason;
}
function user_create($args)
{
$this->newuser = true;
return $args;
}
function login_after($args)
{
if ($this->newuser && $this->check_host_login_exceptions()) {
$args['_task'] = 'settings';
$args['_action'] = 'plugin.password';
$args['_first'] = 'true';
}
return $args;
}
// Check if host and login is allowed to change the password, false = not allowed, true = not allowed
private function check_host_login_exceptions()
{
$rcmail = rcmail::get_instance();
// Host exceptions
$hosts = $rcmail->config->get('password_hosts');
if (!empty($hosts) && !in_array($_SESSION['storage_host'], $hosts)) {
return false;
}
// Login exceptions
if ($exceptions = $rcmail->config->get('password_login_exceptions')) {
$exceptions = array_map('trim', (array) $exceptions);
$exceptions = array_filter($exceptions);
$username = $_SESSION['username'];
foreach ($exceptions as $ec) {
if ($username === $ec) {
return false;
}
}
}
return true;
}
+
+ /**
+ * Hashes a password and returns the hash based on the specified method
+ *
+ * Parts of the code originally from the phpLDAPadmin development team
+ * http://phpldapadmin.sourceforge.net/
+ *
+ * @param string Clear password
+ * @param string Hashing method
+ * @param bool|string Prefix string or TRUE to add a default prefix
+ *
+ * @return string Hashed password
+ */
+ static function hash_password($password, $method = '', $prefixed = true)
+ {
+ $method = strtolower($method);
+ $rcmail = rcmail::get_instance();
+
+ if (empty($method) || $method == 'default') {
+ $method = $rcmail->config->get('password_algorithm');
+ $prefixed = $rcmail->config->get('password_algorithm_prefix');
+ $default = true;
+ }
+ else if ($method == 'crypt') { // deprecated
+ if (!($method = $rcmail->config->get('password_crypt_hash'))) {
+ $method = 'md5';
+ }
+
+ if (!strpos($method, '-crypt')) {
+ $method .= '-crypt';
+ }
+ }
+
+ switch ($method) {
+ case 'des':
+ case 'des-crypt':
+ $crypted = crypt($password, self::random_salt(2));
+ $prefix = '{CRYPT}';
+ break;
+
+ case 'ext_des': // for BC
+ case 'ext-des-crypt':
+ $crypted = crypt($password, '_' . self::random_salt(8));
+ $prefix = '{CRYPT}';
+ break;
+
+ case 'md5crypt': // for BC
+ case 'md5-crypt':
+ $crypted = crypt($password, '$1$' . self::random_salt(9));
+ $prefix = '{CRYPT}';
+ break;
+
+ case 'sha256-crypt':
+ $crypted = crypt($password, '$5$' . self::random_salt(16));
+ $prefix = '{CRYPT}';
+ break;
+
+ case 'sha512-crypt':
+ $crypted = crypt($password, '$6$' . self::random_salt(16));
+ $prefix = '{CRYPT}';
+ break;
+
+ case 'blowfish': // for BC
+ case 'blowfish-crypt':
+ $cost = (int) $rcmail->config->get('password_blowfish_cost');
+ $cost = $cost < 4 || $cost > 31 ? 12 : $cost;
+ $prefix = sprintf('$2a$%02d$', $cost);
+
+ $crypted = crypt($password, $prefix . self::random_salt(22));
+ $prefix = '{CRYPT}';
+ break;
+
+ case 'md5':
+ $crypted = base64_encode(pack('H*', md5($password)));
+ $prefix = '{MD5}';
+ break;
+
+ case 'sha':
+ if (function_exists('sha1')) {
+ $crypted = pack('H*', sha1($password));
+ }
+ else if (function_exists('hash')) {
+ $crypted = hash('sha1', $password, true);
+ }
+ else if (function_exists('mhash')) {
+ $crypted = mhash(MHASH_SHA1, $password);
+ }
+ else {
+ rcube::raise_error(array(
+ 'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Password plugin: Your PHP install does not have the mhash()/hash() nor sha1() function"
+ ), true, true);
+ }
+
+ $crypted = base64_encode($crypted);
+ $prefix = '{SHA}';
+ break;
+
+ case 'ssha':
+ $salt = substr(pack('h*', md5(mt_rand())), 0, 8);
+
+ if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
+ $salt = mhash_keygen_s2k(MHASH_SHA1, $password, $salt, 4);
+ $crypted = mhash(MHASH_SHA1, $password . $salt);
+ }
+ else if (function_exists('sha1')) {
+ $salt = substr(pack("H*", sha1($salt . $password)), 0, 4);
+ $crypted = sha1($password . $salt, true);
+ }
+ else if (function_exists('hash')) {
+ $salt = substr(pack("H*", hash('sha1', $salt . $password)), 0, 4);
+ $crypted = hash('sha1', $password . $salt, true);
+ }
+ else {
+ rcube::raise_error(array(
+ 'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Password plugin: Your PHP install does not have the mhash()/hash() nor sha1() function"
+ ), true, true);
+ }
+
+ $crypted = base64_encode($crypted . $salt);
+ $prefix = '{SSHA}';
+ break;
+
+ case 'smd5':
+ $salt = substr(pack('h*', md5(mt_rand())), 0, 8);
+
+ if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) {
+ $salt = mhash_keygen_s2k(MHASH_MD5, $password, $salt, 4);
+ $crypted = mhash(MHASH_MD5, $password . $salt);
+ }
+ else if (function_exists('hash')) {
+ $salt = substr(pack("H*", hash('md5', $salt . $password)), 0, 4);
+ $crypted = hash('md5', $password . $salt, true);
+ }
+ else {
+ $salt = substr(pack("H*", md5($salt . $password)), 0, 4);
+ $crypted = md5($password . $salt, true);
+ }
+
+ $crypted = base64_encode($crypted . $salt);
+ $prefix = '{SMD5}';
+ break;
+
+ case 'samba':
+ if (function_exists('hash')) {
+ $crypted = hash('md4', rcube_charset::convert($password, RCUBE_CHARSET, 'UTF-16LE'));
+ $crypted = strtoupper($crypted_password);
+ }
+ else {
+ rcube::raise_error(array(
+ 'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Password plugin: Your PHP install does not have hash() function"
+ ), true, true);
+ }
+ break;
+
+ case 'ad':
+ $crypted = rcube_charset::convert('"' . $password . '"', RCUBE_CHARSET, 'UTF-16LE');
+ break;
+
+ case 'cram-md5': // deprecated
+ require_once __DIR__ . '/../helpers/dovecot_hmacmd5.php';
+ $crypted = dovecot_hmacmd5($password);
+ $prefix = '{CRAM-MD5}';
+ break;
+
+ case 'dovecot':
+ if (!($dovecotpw = $rcmail->config->get('password_dovecotpw'))) {
+ $dovecotpw = 'dovecotpw';
+ }
+ if (!($method = $rcmail->config->get('password_dovecotpw_method'))) {
+ $method = 'CRAM-MD5';
+ }
+
+ // use common temp dir
+ $tmp_dir = $rcmail->config->get('temp_dir');
+ $tmpfile = tempnam($tmp_dir, 'roundcube-');
+
+ $pipe = popen("$dovecotpw -s '$method' > '$tmpfile'", "w");
+ if (!$pipe) {
+ unlink($tmpfile);
+ return false;
+ }
+ else {
+ fwrite($pipe, $passwd . "\n", 1+strlen($passwd)); usleep(1000);
+ fwrite($pipe, $passwd . "\n", 1+strlen($passwd));
+ pclose($pipe);
+
+ $crypted = trim(file_get_contents($tmpfile), "\n");
+ unlink($tmpfile);
+
+ if (!preg_match('/^\{' . $method . '\}/', $newpass)) {
+ return false;
+ }
+
+ if (!$default) {
+ $prefixed = (bool) $rcmail->config->get('password_dovecotpw_with_method');
+ }
+
+ if (!$prefixed) {
+ $crypted = trim(str_replace('{' . $method . '}', '', $crypted));
+ }
+
+ $prefixed = false;
+ }
+
+ break;
+
+ case 'hash': // deprecated
+ if (!extension_loaded('hash')) {
+ rcube::raise_error(array(
+ 'code' => 600, 'file' => __FILE__, 'line' => __LINE__,
+ 'message' => "Password plugin: 'hash' extension not loaded!"
+ ), true, true);
+ }
+
+ if (!($hash_algo = strtolower($rcmail->config->get('password_hash_algorithm')))) {
+ $hash_algo = 'sha1';
+ }
+
+ $crypted = hash($hash_algo, $password);
+
+ if ($rcmail->config->get('password_hash_base64')) {
+ $crypted = base64_encode(pack('H*', $crypted));
+ }
+
+ break;
+
+ case 'clear':
+ $crypted = $password;
+ }
+
+ if ($crypted === null || $crypted === false) {
+ return false;
+ }
+
+ if ($prefixed && $prefixed !== true) {
+ $prefix = $prefixed;
+ $prefixed = true;
+ }
+
+ if ($prefixed === true && $prefix) {
+ $crypted = $prefix . $crypted;
+ }
+
+ return $crypted;
+ }
+
+ /**
+ * Used to generate a random salt for crypt-style passwords
+ *
+ * Code originaly from the phpLDAPadmin development team
+ * http://phpldapadmin.sourceforge.net/
+ */
+ static function random_salt($length)
+ {
+ $possible = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ./';
+ $str = '';
+
+ while (strlen($str) < $length) {
+ $str .= substr($possible, (rand() % strlen($possible)), 1);
+ }
+
+ return $str;
+ }
}

File Metadata

Mime Type
text/x-diff
Expires
Tue, Feb 3, 11:38 AM (1 d, 5 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
427157
Default Alt Text
(81 KB)

Event Timeline