diff options
author | thomascube <thomas@roundcube.net> | 2011-08-16 19:44:01 +0000 |
---|---|---|
committer | thomascube <thomas@roundcube.net> | 2011-08-16 19:44:01 +0000 |
commit | 5375e84b75eb23e730f9fd44d042a413970bdc7f (patch) | |
tree | 6cb6d62fdd5aa764a64cb7c522d813e8a408e406 /plugins/password | |
parent | af80aae480b28a82a1c248bfdd6abf96b02ae6d8 (diff) |
Copying plugins into 0.6 release branch
Diffstat (limited to 'plugins/password')
52 files changed, 3771 insertions, 0 deletions
diff --git a/plugins/password/README b/plugins/password/README new file mode 100644 index 000000000..d9280fb03 --- /dev/null +++ b/plugins/password/README @@ -0,0 +1,264 @@ + ----------------------------------------------------------------------- + Password Plugin for Roundcube + ----------------------------------------------------------------------- + + Plugin that adds a possibility to change user password using many + methods (drivers) via Settings/Password tab. + + ----------------------------------------------------------------------- + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + 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, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + @version @package_version@ + @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl> + @author <see driver files for driver authors> + ----------------------------------------------------------------------- + + 1. Configuration + 2. Drivers + 2.1. Database (sql) + 2.2. Cyrus/SASL (sasl) + 2.3. Poppassd/Courierpassd (poppassd) + 2.4. LDAP (ldap) + 2.5. DirectAdmin Control Panel (directadmin) + 2.6. cPanel (cpanel) + 2.7. XIMSS/Communigate (ximms) + 2.8. Virtualmin (virtualmin) + 2.9. hMailServer (hmail) + 2.10. PAM (pam) + 2.11. Chpasswd (chpasswd) + 2.12. LDAP - no PEAR (ldap_simple) + 2.13. XMail (xmail) + 3. Driver API + + + 1. Configuration + ---------------- + + Copy config.inc.php.dist to config.inc.php and set the options as described + within the file. + + + 2. Drivers + ---------- + + Password plugin supports many password change mechanisms which are + handled by included drivers. Just pass driver name in 'password_driver' option. + + + 2.1. Database (sql) + ------------------- + + You can specify which database to connect by 'password_db_dsn' option and + what SQL query to execute by 'password_query'. See main.inc.php.dist file for + more info. + + Example implementations of an update_passwd function: + + - This is for use with LMS (http://lms.org.pl) database and postgres: + + CREATE OR REPLACE FUNCTION update_passwd(hash text, account text) RETURNS integer AS $$ + DECLARE + res integer; + BEGIN + UPDATE passwd SET password = hash + WHERE login = split_part(account, '@', 1) + AND domainid = (SELECT id FROM domains WHERE name = split_part(account, '@', 2)) + RETURNING id INTO res; + RETURN res; + END; + $$ LANGUAGE plpgsql SECURITY DEFINER; + + - This is for use with a SELECT update_passwd(%o,%c,%u) query + Updates the password only when the old password matches the MD5 password + in the database + + CREATE FUNCTION update_password (oldpass text, cryptpass text, user text) RETURNS text + MODIFIES SQL DATA + BEGIN + DECLARE currentsalt varchar(20); + DECLARE error text; + SET error = 'incorrect current password'; + SELECT substring_index(substr(user.password,4),_latin1'$',1) INTO currentsalt FROM users WHERE username=user; + SELECT '' INTO error FROM users WHERE username=user AND password=ENCRYPT(oldpass,currentsalt); + UPDATE users SET password=cryptpass WHERE username=user AND password=ENCRYPT(oldpass,currentsalt); + RETURN error; + END + + Example SQL UPDATEs: + + - Plain text passwords: + UPDATE users SET password=%p WHERE username=%u AND password=%o AND domain=%h LIMIT 1 + + - Crypt text passwords: + UPDATE users SET password=%c WHERE username=%u LIMIT 1 + + - Use a MYSQL crypt function (*nix only) with random 8 character salt + UPDATE users SET password=ENCRYPT(%p,concat(_utf8'$1$',right(md5(rand()),8),_utf8'$')) WHERE username=%u LIMIT 1 + + - MD5 stored passwords: + UPDATE users SET password=MD5(%p) WHERE username=%u AND password=MD5(%o) LIMIT 1 + + + 2.2. Cyrus/SASL (sasl) + ---------------------- + + Cyrus SASL database authentication allows your Cyrus+Roundcube + installation to host mail users without requiring a Unix Shell account! + + This driver only covers the "sasldb" case when using Cyrus SASL. Kerberos + and PAM authentication mechanisms will require other techniques to enable + user password manipulations. + + Cyrus SASL includes a shell utility called "saslpasswd" for manipulating + user passwords in the "sasldb" database. This plugin attempts to use + this utility to perform password manipulations required by your webmail + users without any administrative interaction. Unfortunately, this + scheme requires that the "saslpasswd" utility be run as the "cyrus" + user - kind of a security problem since we have chosen to SUID a small + script which will allow this to happen. + + This driver is based on the Squirrelmail Change SASL Password Plugin. + See http://www.squirrelmail.org/plugin_view.php?id=107 for details. + + Installation: + + Change into the drivers directory. Edit the chgsaslpasswd.c file as is + documented within it. + + Compile the wrapper program: + gcc -o chgsaslpasswd chgsaslpasswd.c + + Chown the compiled chgsaslpasswd binary to the cyrus user and group + that your browser runs as, then chmod them to 4550. + + For example, if your cyrus user is 'cyrus' and the apache server group is + 'nobody' (I've been told Redhat runs Apache as user 'apache'): + + chown cyrus:nobody chgsaslpasswd + chmod 4550 chgsaslpasswd + + Stephen Carr has suggested users should try to run the scripts on a test + account as the cyrus user eg; + + su cyrus -c "./chgsaslpasswd -p test_account" + + This will allow you to make sure that the script will work for your setup. + Should the script not work, make sure that: + 1) the user the script runs as has access to the saslpasswd|saslpasswd2 + file and proper permissions + 2) make sure the user in the chgsaslpasswd.c file is set correctly. + This could save you some headaches if you are the paranoid type. + + + 2.3. Poppassd/Courierpassd (poppassd) + ------------------------------------- + + You can specify which host to connect to via 'password_pop_host' and + what port via 'password_pop_port'. See config.inc.php.dist file for more info. + + + 2.4. LDAP (ldap) + ---------------- + + See config.inc.php.dist file. Requires PEAR::Net_LDAP2 package. + + + 2.5. DirectAdmin Control Panel (directadmin) + -------------------------------------------- + + You can specify which host to connect to via 'password_directadmin_host' (don't + forget to use tcp:// or ssl://) and what port via 'password_direactadmin_port'. + The password enforcement with plenty customization can be done directly by + DirectAdmin, please see http://www.directadmin.com/features.php?id=910 + See config.inc.php.dist file for more info. + + + 2.6. cPanel (cpanel) + -------------------- + + You can specify parameters for HTTP connection to cPanel's admin + interface. See config.inc.php.dist file for more info. + + + 2.7. XIMSS/Communigate (ximms) + ------------------------------ + + You can specify which host and port to connect to via 'password_ximss_host' + and 'password_ximss_port'. See config.inc.php.dist file for more info. + + + 2.8. Virtualmin (virtualmin) + ---------------------------- + + As in sasl driver this one allows to change password using shell + utility called "virtualmin". See drivers/chgvirtualminpasswd.c for + installation instructions. See also config.inc.php.dist file. + + + 2.9. hMailServer (hmail) + ------------------------ + + Requires PHP COM (Windows only). For access to hMail server on remote host + you'll need to define 'hmailserver_remote_dcom' and 'hmailserver_server'. + See config.inc.php.dist file for more info. + + + 2.10. PAM (pam) + --------------- + + This driver is for changing passwords of shell users authenticated with PAM. + Requires PECL's PAM exitension to be installed (http://pecl.php.net/package/PAM). + + + 2.11. Chpasswd (chpasswd) + ------------------------- + + Driver that adds functionality to change the systems user password via + the 'chpasswd' command. See config.inc.php.dist file. + + Attached wrapper script (chpass-wrapper.py) restricts password changes + to uids >= 1000 and can deny requests based on a blacklist. + + + 2.12. LDAP - no PEAR (ldap_simple) + ----------------------------------- + + It's rewritten ldap driver that doesn't require the Net_LDAP2 PEAR extension. + It uses directly PHP's ldap module functions instead (as Roundcube does). + + This driver is fully compatible with the ldap driver, but + does not require (or uses) the + $rcmail_config['password_ldap_force_replace'] variable. + Other advantages: + * Connects only once with the LDAP server when using the search user. + * Does not read the DN, but only replaces the password within (that is + why the 'force replace' is always used). + + + 2.13. XMail (xmail) + ----------------------------------- + + Driver for XMail (www.xmailserver.org). See config.inc.php.dist file + for configuration description. + + + 3. Driver API + ------------- + + Driver file (<driver_name>.php) must define 'password_save' function with + two arguments. First - current password, second - new password. Function + should return PASSWORD_SUCCESS on success or any of PASSWORD_CONNECT_ERROR, + PASSWORD_CRYPT_ERROR, PASSWORD_ERROR when driver was unable to change password. + Extended result (as a hash-array with 'message' and 'code' items) can be returned + too. See existing drivers in drivers/ directory for examples. diff --git a/plugins/password/config.inc.php.dist b/plugins/password/config.inc.php.dist new file mode 100644 index 000000000..94af6d776 --- /dev/null +++ b/plugins/password/config.inc.php.dist @@ -0,0 +1,303 @@ +<?php + +// Password Plugin options +// ----------------------- +// A driver to use for password change. Default: "sql". +// See README file for list of supported driver names. +$rcmail_config['password_driver'] = 'sql'; + +// Determine whether current password is required to change password. +// Default: false. +$rcmail_config['password_confirm_current'] = true; + +// Require the new password to be a certain length. +// set to blank to allow passwords of any length +$rcmail_config['password_minimum_length'] = 0; + +// Require the new password to contain a letter and punctuation character +// Change to false to remove this check. +$rcmail_config['password_require_nonalpha'] = false; + +// Enables logging of password changes into logs/password +$rcmail_config['password_log'] = false; + + +// SQL Driver options +// ------------------ +// PEAR database DSN for performing the query. By default +// Roundcube DB settings are used. +$rcmail_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. +// %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 +// %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) +// Escaping of macros is handled by this module. +// Default: "SELECT update_passwd(%c, %u)" +$rcmail_config['password_query'] = 'SELECT update_passwd(%c, %u)'; + +// Path for dovecotpw (if not in $PATH) +// $rcmail_config['password_dovecotpw'] = '/usr/local/sbin/dovecotpw'; + +// Dovecot method (dovecotpw -s 'method') +$rcmail_config['password_dovecotpw_method'] = 'CRAM-MD5'; + +// Enables use of password with crypt method prefix in %D, e.g. {MD5}$1$LUiMYWqx$fEkg/ggr/L6Mb2X7be4i1/ +$rcmail_config['password_dovecotpw_with_method'] = false; + +// Using a password hash for %n and %q variables. +// 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. +$rcmail_config['password_hash_algorithm'] = 'sha1'; + +// You can also decide whether the hash should be provided +// as hex string or in base64 encoded format. +$rcmail_config['password_hash_base64'] = false; + + +// Poppassd Driver options +// ----------------------- +// The host which changes the password +$rcmail_config['password_pop_host'] = 'localhost'; + +// TCP port used for poppassd connections +$rcmail_config['password_pop_port'] = 106; + + +// SASL Driver options +// ------------------- +// Additional arguments for the saslpasswd2 call +$rcmail_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' +$rcmail_config['password_ldap_host'] = 'localhost'; + +// LDAP server port to connect to +// Default: '389' +$rcmail_config['password_ldap_port'] = '389'; + +// TLS is started after connecting +// Using TLS for password modification is recommanded. +// Default: false +$rcmail_config['password_ldap_starttls'] = false; + +// LDAP version +// Default: '3' +$rcmail_config['password_ldap_version'] = '3'; + +// LDAP base name (root directory) +// Exemple: 'dc=exemple,dc=com' +$rcmail_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' +$rcmail_config['password_ldap_method'] = 'user'; + +// LDAP Admin DN +// Used only in admin connection mode +// Default: null +$rcmail_config['password_ldap_adminDN'] = null; + +// LDAP Admin Password +// Used only in admin connection mode +// Default: null +$rcmail_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' +$rcmail_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. +$rcmail_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. +$rcmail_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. +$rcmail_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))' +$rcmail_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, 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. +// Default: 'crypt' +$rcmail_config['password_ldap_encodage'] = 'crypt'; + +// LDAP password attribute +// Name of the ldap's attribute used for storing user password +// Default: 'userPassword' +$rcmail_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 +$rcmail_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) +$rcmail_config['password_ldap_lchattr'] = ''; + +// LDAP Samba password attribute, e.g. sambaNTPassword +// Name of the LDAP's Samba attribute used for storing user password +$rcmail_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 +$rcmail_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) +$rcmail_config['password_directadmin_host'] = 'tcp://localhost'; + +// TCP port used for DirectAdmin connections +$rcmail_config['password_directadmin_port'] = 2222; + + +// vpopmaild Driver options +// ----------------------- +// The host which changes the password +$rcmail_config['password_vpopmaild_host'] = 'localhost'; + +// TCP port used for vpopmaild connections +$rcmail_config['password_vpopmaild_port'] = 89; + + +// cPanel Driver options +// -------------------------- +// The cPanel Host name +$rcmail_config['password_cpanel_host'] = 'host.domain.com'; + +// The cPanel admin username +$rcmail_config['password_cpanel_username'] = 'username'; + +// The cPanel admin password +$rcmail_config['password_cpanel_password'] = 'password'; + +// The cPanel port to use +$rcmail_config['password_cpanel_port'] = 2082; + +// Using ssl for cPanel connections? +$rcmail_config['password_cpanel_ssl'] = true; + +// The cPanel theme in use +$rcmail_config['password_cpanel_theme'] = 'x'; + + +// XIMSS (Communigate server) Driver options +// ----------------------------------------- +// Host name of the Communigate server +$rcmail_config['password_ximss_host'] = 'mail.example.com'; + +// XIMSS port on Communigate server +$rcmail_config['password_ximss_port'] = 11024; + + +// chpasswd Driver options +// --------------------- +// Command to use +$rcmail_config['password_chpasswd_cmd'] = 'sudo /usr/sbin/chpasswd 2> /dev/null'; + + +// XMail Driver options +// --------------------- +$rcmail_config['xmail_host'] = 'localhost'; +$rcmail_config['xmail_user'] = 'YourXmailControlUser'; +$rcmail_config['xmail_pass'] = 'YourXmailControlPass'; +$rcmail_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 +$rcmail_config['hmailserver_remote_dcom'] = false; +// Windows credentials +$rcmail_config['hmailserver_server'] = array( + '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 +$rcmail_config['password_virtualmin_format'] = 0; diff --git a/plugins/password/drivers/chgsaslpasswd.c b/plugins/password/drivers/chgsaslpasswd.c new file mode 100644 index 000000000..bcdcb2e0d --- /dev/null +++ b/plugins/password/drivers/chgsaslpasswd.c @@ -0,0 +1,29 @@ +#include <stdio.h> +#include <unistd.h> + +// set the UID this script will run as (cyrus user) +#define UID 96 +// set the path to saslpasswd or saslpasswd2 +#define CMD "/usr/sbin/saslpasswd2" + +/* INSTALLING: + gcc -o chgsaslpasswd chgsaslpasswd.c + chown cyrus.apache chgsaslpasswd + strip chgsaslpasswd + chmod 4550 chgsaslpasswd +*/ + +main(int argc, char *argv[]) +{ + int rc,cc; + + cc = setuid(UID); + rc = execvp(CMD, argv); + if ((rc != 0) || (cc != 0)) + { + fprintf(stderr, "__ %s: failed %d %d\n", argv[0], rc, cc); + return 1; + } + + return 0; +} diff --git a/plugins/password/drivers/chgvirtualminpasswd.c b/plugins/password/drivers/chgvirtualminpasswd.c new file mode 100644 index 000000000..4e2299c66 --- /dev/null +++ b/plugins/password/drivers/chgvirtualminpasswd.c @@ -0,0 +1,28 @@ +#include <stdio.h> +#include <unistd.h> + +// set the UID this script will run as (root user) +#define UID 0 +#define CMD "/usr/sbin/virtualmin" + +/* INSTALLING: + gcc -o chgvirtualminpasswd chgvirtualminpasswd.c + chown root.apache chgvirtualminpasswd + strip chgvirtualminpasswd + chmod 4550 chgvirtualminpasswd +*/ + +main(int argc, char *argv[]) +{ + int rc,cc; + + cc = setuid(UID); + rc = execvp(CMD, argv); + if ((rc != 0) || (cc != 0)) + { + fprintf(stderr, "__ %s: failed %d %d\n", argv[0], rc, cc); + return 1; + } + + return 0; +} diff --git a/plugins/password/drivers/chpass-wrapper.py b/plugins/password/drivers/chpass-wrapper.py new file mode 100644 index 000000000..61bba849e --- /dev/null +++ b/plugins/password/drivers/chpass-wrapper.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python + +import sys +import pwd +import subprocess + +BLACKLIST = ( + # add blacklisted users here + #'user1', +) + +try: + username, password = sys.stdin.readline().split(':', 1) +except ValueError, e: + sys.exit('Malformed input') + +try: + user = pwd.getpwnam(username) +except KeyError, e: + sys.exit('No such user: %s' % username) + +if user.pw_uid < 1000: + sys.exit('Changing the password for user id < 1000 is forbidden') + +if username in BLACKLIST: + sys.exit('Changing password for user %s is forbidden (user blacklisted)' % + username) + +handle = subprocess.Popen('/usr/sbin/chpasswd', stdin = subprocess.PIPE) +handle.communicate('%s:%s' % (username, password)) + +sys.exit(handle.returncode) diff --git a/plugins/password/drivers/chpasswd.php b/plugins/password/drivers/chpasswd.php new file mode 100644 index 000000000..28c3e5d7a --- /dev/null +++ b/plugins/password/drivers/chpasswd.php @@ -0,0 +1,36 @@ +<?php + +/** + * chpasswd Driver + * + * Driver that adds functionality to change the systems user password via + * the 'chpasswd' command. + * + * For installation instructions please read the README file. + * + * @version 1.0 + * @author Alex Cartwright <acartwright@mutinydesign.co.uk) + */ + +function password_save($currpass, $newpass) +{ + $cmd = rcmail::get_instance()->config->get('password_chpasswd_cmd'); + $username = $_SESSION['username']; + + $handle = popen($cmd, "w"); + fwrite($handle, "$username:$newpass\n"); + + if (pclose($handle) == 0) { + return PASSWORD_SUCCESS; + } + else { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: Unable to execute $cmd" + ), true, false); + } + + return PASSWORD_ERROR; +} diff --git a/plugins/password/drivers/cpanel.php b/plugins/password/drivers/cpanel.php new file mode 100644 index 000000000..82bfe74d2 --- /dev/null +++ b/plugins/password/drivers/cpanel.php @@ -0,0 +1,121 @@ +<?php + +/** + * cPanel Password Driver + * + * Driver that adds functionality to change the users cPanel password. + * The cPanel PHP API code has been taken from: http://www.phpclasses.org/browse/package/3534.html + * + * This driver has been tested with Hostmonster hosting and seems to work fine. + + * + * @version 1.0 + * @author Fulvio Venturelli <fulvio@venturelli.org> + */ + +class HTTP +{ + function HTTP($host, $username, $password, $port, $ssl, $theme) + { + $this->ssl = $ssl ? 'ssl://' : ''; + $this->username = $username; + $this->password = $password; + $this->theme = $theme; + $this->auth = base64_encode($username . ':' . $password); + $this->port = $port; + $this->host = $host; + $this->path = '/frontend/' . $theme . '/'; + } + + function getData($url, $data = '') + { + $url = $this->path . $url; + if(is_array($data)) + { + $url = $url . '?'; + foreach($data as $key=>$value) + { + $url .= urlencode($key) . '=' . urlencode($value) . '&'; + } + $url = substr($url, 0, -1); + } + $response = ''; + $fp = fsockopen($this->ssl . $this->host, $this->port); + if(!$fp) + { + return false; + } + $out = 'GET ' . $url . ' HTTP/1.0' . "\r\n"; + $out .= 'Authorization: Basic ' . $this->auth . "\r\n"; + $out .= 'Connection: Close' . "\r\n\r\n"; + fwrite($fp, $out); + while (!feof($fp)) + { + $response .= @fgets($fp); + } + fclose($fp); + return $response; + } +} + + +class emailAccount +{ + function emailAccount($host, $username, $password, $port, $ssl, $theme, $address) + { + $this->HTTP = new HTTP($host, $username, $password, $port, $ssl, $theme); + if(strpos($address, '@')) + { + list($this->email, $this->domain) = explode('@', $address); + } + else + { + list($this->email, $this->domain) = array($address, ''); + } + } + + /* + * Change email account password + * + * Returns true on success or false on failure. + * @param string $password email account password + * @return bool + */ + function setPassword($password) + { + $data['email'] = $this->email; + $data['domain'] = $this->domain; + $data['password'] = $password; + $response = $this->HTTP->getData('mail/dopasswdpop.html', $data); + if(strpos($response, 'success') && !strpos($response, 'failure')) + { + return true; + } + return false; + } +} + + +function password_save($curpas, $newpass) +{ + $rcmail = rcmail::get_instance(); + + // Create a cPanel email object + $cPanel = new emailAccount($rcmail->config->get('password_cpanel_host'), + $rcmail->config->get('password_cpanel_username'), + $rcmail->config->get('password_cpanel_password'), + $rcmail->config->get('password_cpanel_port'), + $rcmail->config->get('password_cpanel_ssl'), + $rcmail->config->get('password_cpanel_theme'), + $_SESSION['username'] ); + + if ($cPanel->setPassword($newpass)){ + return PASSWORD_SUCCESS; + } + else + { + return PASSWORD_ERROR; + } +} + +?> diff --git a/plugins/password/drivers/directadmin.php b/plugins/password/drivers/directadmin.php new file mode 100644 index 000000000..3b6ae9f03 --- /dev/null +++ b/plugins/password/drivers/directadmin.php @@ -0,0 +1,489 @@ +<?php + +/** + * DirectAdmin Password Driver + * + * Driver to change passwords via DirectAdmin Control Panel + * + * @version 1.2 + * @author Victor Benincasa <vbenincasa@gmail.com> + * + */ + + +function password_save($curpass, $passwd){ + + $rcmail = rcmail::get_instance(); + $Socket = new HTTPSocket; + + $da_user = $_SESSION['username']; + $da_curpass = $curpass; + $da_newpass = $passwd; + $da_host = $rcmail->config->get('password_directadmin_host'); + $da_port = $rcmail->config->get('password_directadmin_port'); + + if(strpos($da_user, '@') === false) return array('code' => PASSWORD_ERROR, 'message' => 'Change the SYSTEM user password through control panel!'); + + $da_host = str_replace('%h', $_SESSION['imap_host'], $da_host); + $da_host = str_replace('%d', $rcmail->user->get_username('domain'), $da_host); + + $Socket->connect($da_host,$da_port); + $Socket->set_method('POST'); + $Socket->query('/CMD_CHANGE_EMAIL_PASSWORD', + array( + 'email' => $da_user, + 'oldpassword' => $da_curpass, + 'password1' => $da_newpass, + 'password2' => $da_newpass, + 'api' => '1' + )); + $response = $Socket->fetch_parsed_body(); + + //DEBUG + //console("Password Plugin: [USER: $da_user] [HOST: $da_host] - Response: [SOCKET: ".$Socket->result_status_code."] [DA ERROR: ".strip_tags($response['error'])."] [TEXT: ".$response[text]."]"); + + if($Socket->result_status_code != 200) + return array('code' => PASSWORD_CONNECT_ERROR, 'message' => $Socket->error[0]); + elseif($response['error'] == 1) + return array('code' => PASSWORD_ERROR, 'message' => strip_tags($response['text'])); + else + return PASSWORD_SUCCESS; + +} + + +/** + * Socket communication class. + * + * Originally designed for use with DirectAdmin's API, this class will fill any HTTP socket need. + * + * Very, very basic usage: + * $Socket = new HTTPSocket; + * echo $Socket->get('http://user:pass@somesite.com/somedir/some.file?query=string&this=that'); + * + * @author Phi1 'l0rdphi1' Stier <l0rdphi1@liquenox.net> + * @package HTTPSocket + * @version 2.7 (Updated by Victor Benincasa <vbenincasa@gmail.com>) + */ +class HTTPSocket { + + var $version = '2.7'; + + /* all vars are private except $error, $query_cache, and $doFollowLocationHeader */ + + var $method = 'GET'; + + var $remote_host; + var $remote_port; + var $remote_uname; + var $remote_passwd; + + var $result; + var $result_header; + var $result_body; + var $result_status_code; + + var $lastTransferSpeed; + + var $bind_host; + + var $error = array(); + var $warn = array(); + var $query_cache = array(); + + var $doFollowLocationHeader = TRUE; + var $redirectURL; + + var $extra_headers = array(); + + /** + * Create server "connection". + * + */ + function connect($host, $port = '' ) + { + if (!is_numeric($port)) + { + $port = 80; + } + + $this->remote_host = $host; + $this->remote_port = $port; + } + + function bind( $ip = '' ) + { + if ( $ip == '' ) + { + $ip = $_SERVER['SERVER_ADDR']; + } + + $this->bind_host = $ip; + } + + /** + * Change the method being used to communicate. + * + * @param string|null request method. supports GET, POST, and HEAD. default is GET + */ + function set_method( $method = 'GET' ) + { + $this->method = strtoupper($method); + } + + /** + * Specify a username and password. + * + * @param string|null username. defualt is null + * @param string|null password. defualt is null + */ + function set_login( $uname = '', $passwd = '' ) + { + if ( strlen($uname) > 0 ) + { + $this->remote_uname = $uname; + } + + if ( strlen($passwd) > 0 ) + { + $this->remote_passwd = $passwd; + } + + } + + /** + * Query the server + * + * @param string containing properly formatted server API. See DA API docs and examples. Http:// URLs O.K. too. + * @param string|array query to pass to url + * @param int if connection KB/s drops below value here, will drop connection + */ + function query( $request, $content = '', $doSpeedCheck = 0 ) + { + $this->error = $this->warn = array(); + $this->result_status_code = NULL; + + // is our request a http:// ... ? + if (preg_match('!^http://!i',$request)) + { + $location = parse_url($request); + $this->connect($location['host'],$location['port']); + $this->set_login($location['user'],$location['pass']); + + $request = $location['path']; + $content = $location['query']; + + if ( strlen($request) < 1 ) + { + $request = '/'; + } + + } + + $array_headers = array( + 'User-Agent' => "HTTPSocket/$this->version", + 'Host' => ( $this->remote_port == 80 ? $this->remote_host : "$this->remote_host:$this->remote_port" ), + 'Accept' => '*/*', + 'Connection' => 'Close' ); + + foreach ( $this->extra_headers as $key => $value ) + { + $array_headers[$key] = $value; + } + + $this->result = $this->result_header = $this->result_body = ''; + + // was content sent as an array? if so, turn it into a string + if (is_array($content)) + { + $pairs = array(); + + foreach ( $content as $key => $value ) + { + $pairs[] = "$key=".urlencode($value); + } + + $content = join('&',$pairs); + unset($pairs); + } + + $OK = TRUE; + + // instance connection + if ($this->bind_host) + { + $socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); + socket_bind($socket,$this->bind_host); + + if (!@socket_connect($socket,$this->remote_host,$this->remote_port)) + { + $OK = FALSE; + } + + } + else + { + $socket = @fsockopen( $this->remote_host, $this->remote_port, $sock_errno, $sock_errstr, 10 ); + } + + if ( !$socket || !$OK ) + { + $this->error[] = "Can't create socket connection to $this->remote_host:$this->remote_port."; + return 0; + } + + // if we have a username and password, add the header + if ( isset($this->remote_uname) && isset($this->remote_passwd) ) + { + $array_headers['Authorization'] = 'Basic '.base64_encode("$this->remote_uname:$this->remote_passwd"); + } + + // for DA skins: if $this->remote_passwd is NULL, try to use the login key system + if ( isset($this->remote_uname) && $this->remote_passwd == NULL ) + { + $array_headers['Cookie'] = "session={$_SERVER['SESSION_ID']}; key={$_SERVER['SESSION_KEY']}"; + } + + // if method is POST, add content length & type headers + if ( $this->method == 'POST' ) + { + $array_headers['Content-type'] = 'application/x-www-form-urlencoded'; + $array_headers['Content-length'] = strlen($content); + } + // else method is GET or HEAD. we don't support anything else right now. + else + { + if ($content) + { + $request .= "?$content"; + } + } + + // prepare query + $query = "$this->method $request HTTP/1.0\r\n"; + foreach ( $array_headers as $key => $value ) + { + $query .= "$key: $value\r\n"; + } + $query .= "\r\n"; + + // if POST we need to append our content + if ( $this->method == 'POST' && $content ) + { + $query .= "$content\r\n\r\n"; + } + + // query connection + if ($this->bind_host) + { + socket_write($socket,$query); + + // now load results + while ( $out = socket_read($socket,2048) ) + { + $this->result .= $out; + } + } + else + { + fwrite( $socket, $query, strlen($query) ); + + // now load results + $this->lastTransferSpeed = 0; + $status = socket_get_status($socket); + $startTime = time(); + $length = 0; + $prevSecond = 0; + while ( !feof($socket) && !$status['timed_out'] ) + { + $chunk = fgets($socket,1024); + $length += strlen($chunk); + $this->result .= $chunk; + + $elapsedTime = time() - $startTime; + + if ( $elapsedTime > 0 ) + { + $this->lastTransferSpeed = ($length/1024)/$elapsedTime; + } + + if ( $doSpeedCheck > 0 && $elapsedTime > 5 && $this->lastTransferSpeed < $doSpeedCheck ) + { + $this->warn[] = "kB/s for last 5 seconds is below 50 kB/s (~".( ($length/1024)/$elapsedTime )."), dropping connection..."; + $this->result_status_code = 503; + break; + } + + } + + if ( $this->lastTransferSpeed == 0 ) + { + $this->lastTransferSpeed = $length/1024; + } + + } + + list($this->result_header,$this->result_body) = preg_split("/\r\n\r\n/",$this->result,2); + + if ($this->bind_host) + { + socket_close($socket); + } + else + { + fclose($socket); + } + + $this->query_cache[] = $query; + + + $headers = $this->fetch_header(); + + // what return status did we get? + if (!$this->result_status_code) + { + preg_match("#HTTP/1\.. (\d+)#",$headers[0],$matches); + $this->result_status_code = $matches[1]; + } + + // did we get the full file? + if ( !empty($headers['content-length']) && $headers['content-length'] != strlen($this->result_body) ) + { + $this->result_status_code = 206; + } + + // now, if we're being passed a location header, should we follow it? + if ($this->doFollowLocationHeader) + { + if ($headers['location']) + { + $this->redirectURL = $headers['location']; + $this->query($headers['location']); + } + } + + } + + function getTransferSpeed() + { + return $this->lastTransferSpeed; + } + + /** + * The quick way to get a URL's content :) + * + * @param string URL + * @param boolean return as array? (like PHP's file() command) + * @return string result body + */ + function get($location, $asArray = FALSE ) + { + $this->query($location); + + if ( $this->get_status_code() == 200 ) + { + if ($asArray) + { + return preg_split("/\n/",$this->fetch_body()); + } + + return $this->fetch_body(); + } + + return FALSE; + } + + /** + * Returns the last status code. + * 200 = OK; + * 403 = FORBIDDEN; + * etc. + * + * @return int status code + */ + function get_status_code() + { + return $this->result_status_code; + } + + /** + * Adds a header, sent with the next query. + * + * @param string header name + * @param string header value + */ + function add_header($key,$value) + { + $this->extra_headers[$key] = $value; + } + + /** + * Clears any extra headers. + * + */ + function clear_headers() + { + $this->extra_headers = array(); + } + + /** + * Return the result of a query. + * + * @return string result + */ + function fetch_result() + { + return $this->result; + } + + /** + * Return the header of result (stuff before body). + * + * @param string (optional) header to return + * @return array result header + */ + function fetch_header( $header = '' ) + { + $array_headers = preg_split("/\r\n/",$this->result_header); + + $array_return = array( 0 => $array_headers[0] ); + unset($array_headers[0]); + + foreach ( $array_headers as $pair ) + { + list($key,$value) = preg_split("/: /",$pair,2); + $array_return[strtolower($key)] = $value; + } + + if ( $header != '' ) + { + return $array_return[strtolower($header)]; + } + + return $array_return; + } + + /** + * Return the body of result (stuff after header). + * + * @return string result body + */ + function fetch_body() + { + return $this->result_body; + } + + /** + * Return parsed body in array format. + * + * @return array result parsed + */ + function fetch_parsed_body() + { + parse_str($this->result_body,$x); + return $x; + } + +} + +?> diff --git a/plugins/password/drivers/hmail.php b/plugins/password/drivers/hmail.php new file mode 100644 index 000000000..39a87ab34 --- /dev/null +++ b/plugins/password/drivers/hmail.php @@ -0,0 +1,61 @@ +<?php + +/** + * hMailserver password driver + * + * @version 1.3 - 05.11.2010 + * @author Roland 'rosali' Liebl <myroundcube@mail4us.net> + * + */ + +function password_save($curpass, $passwd) +{ + $rcmail = rcmail::get_instance(); + + if ($curpass == '' || $passwd == '') + return PASSWORD_ERROR; + + try { + $remote = $rcmail->config->get('hmailserver_remote_dcom', false); + if ($remote) + $obApp = new COM("hMailServer.Application", $rcmail->config->get('hmailserver_server')); + else + $obApp = new COM("hMailServer.Application"); + } + catch (Exception $e) { + write_log('errors', "Plugin password (hmail driver): " . trim(strip_tags($e->getMessage()))); + write_log('errors', "Plugin password (hmail driver): This problem is often caused by DCOM permissions not being set."); + return PASSWORD_ERROR; + } + + $username = $rcmail->user->data['username']; + if (strstr($username,'@')){ + $temparr = explode('@', $username); + $domain = $temparr[1]; + } + else { + $domain = $rcmail->config->get('username_domain',false); + if (!$domain) { + write_log('errors','Plugin password (hmail driver): $rcmail_config[\'username_domain\'] is not defined.'); + write_log('errors','Plugin password (hmail driver): Hint: Use hmail_login plugin (http://myroundcube.googlecode.com'); + return PASSWORD_ERROR; + } + $username = $username . "@" . $domain; + } + + $obApp->Authenticate($username, $curpass); + try { + $obDomain = $obApp->Domains->ItemByName($domain); + $obAccount = $obDomain->Accounts->ItemByAddress($username); + $obAccount->Password = $passwd; + $obAccount->Save(); + return PASSWORD_SUCCESS; + } + catch (Exception $e) { + write_log('errors', "Plugin password (hmail driver): " . trim(strip_tags($e->getMessage()))); + write_log('errors', "Plugin password (hmail driver): This problem is often caused by DCOM permissions not being set."); + return PASSWORD_ERROR; + } +} + +?> diff --git a/plugins/password/drivers/ldap.php b/plugins/password/drivers/ldap.php new file mode 100644 index 000000000..3ea30a69c --- /dev/null +++ b/plugins/password/drivers/ldap.php @@ -0,0 +1,317 @@ +<?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 1.1 (2010-04-07) + * @author Edouard MOREAU <edouard.moreau@ensma.fr> + * + * function hashPassword based on code from the phpLDAPadmin development team (http://phpldapadmin.sourceforge.net/). + * function randomSalt based on code from the phpLDAPadmin development team (http://phpldapadmin.sourceforge.net/). + * + */ + +function password_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 = substitute_vars($userDN); + } else { + $userDN = 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 (PEAR::isError($ldap)) { + return PASSWORD_CONNECT_ERROR; + } + + $crypted_pass = hashPassword($passwd, $rcmail->config->get('password_ldap_encodage')); + $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'); + + // 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 = hashPassword($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) +{ + $ldapConfig = array ( + 'binddn' => $rcmail->config->get('password_ldap_searchDN'), + 'bindpw' => $rcmail->config->get('password_ldap_searchPW'), + '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'), + ); + + $ldap = Net_LDAP2::connect($ldapConfig); + + if (PEAR::isError($ldap)) { + return ''; + } + + $base = $rcmail->config->get('password_ldap_search_base'); + $filter = substitute_vars($rcmail->config->get('password_ldap_search_filter')); + $options = array ( + 'scope' => 'sub', + 'attributes' => array(), + ); + + $result = $ldap->search($base, $filter, $options); + $ldap->done(); + if (PEAR::isError($result) || ($result->count() != 1)) { + return ''; + } + + return $result->current()->dn(); +} + +/** + * Substitute %login, %name, %domain, %dc in $str. + * See plugin config for details. + */ +function substitute_vars($str) +{ + $rcmail = rcmail::get_instance(); + $domain = $rcmail->user->get_username('domain'); + $dc = 'dc='.strtr($domain, array('.' => ',dc=')); // hierarchal domain string + + $str = str_replace(array( + '%login', + '%name', + '%domain', + '%dc', + ), array( + $_SESSION['username'], + $rcmail->user->get_username('local'), + $domain, + $dc, + ), $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. + * + * @param string $passwordClear The password to hash in clear text. + * @param string $encodageType Standard LDAP encryption type which must be one of + * crypt, ext_des, md5crypt, blowfish, md5, sha, smd5, ssha, or clear. + * @return string The hashed password. + * + */ + +function hashPassword( $passwordClear, $encodageType ) +{ + $encodageType = strtolower( $encodageType ); + switch( $encodageType ) { + case 'crypt': + $cryptedPassword = '{CRYPT}' . crypt($passwordClear,randomSalt(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; + } + $cryptedPassword = '{CRYPT}' . crypt( $passwordClear, '_' . randomSalt(8) ); + break; + + case 'md5crypt': + if( ! defined( 'CRYPT_MD5' ) || CRYPT_MD5 == 0 ) { + // Your system crypt library does not support md5crypt encryption. + return FALSE; + } + $cryptedPassword = '{CRYPT}' . crypt( $passwordClear , '$1$' . randomSalt(9) ); + break; + + case 'blowfish': + if( ! defined( 'CRYPT_BLOWFISH' ) || CRYPT_BLOWFISH == 0 ) { + // Your system crypt library does not support blowfish encryption. + return FALSE; + } + // hardcoded to second blowfish version and set number of rounds + $cryptedPassword = '{CRYPT}' . crypt( $passwordClear , '$2a$12$' . randomSalt(13) ); + break; + + case 'md5': + $cryptedPassword = '{MD5}' . base64_encode( pack( 'H*' , md5( $passwordClear) ) ); + break; + + case 'sha': + if( function_exists('sha1') ) { + // use php 4.3.0+ sha1 function, if it is available. + $cryptedPassword = '{SHA}' . base64_encode( pack( 'H*' , sha1( $passwordClear) ) ); + } elseif( function_exists( 'mhash' ) ) { + $cryptedPassword = '{SHA}' . base64_encode( mhash( MHASH_SHA1, $passwordClear) ); + } else { + return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes. + } + break; + + case 'ssha': + if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) { + mt_srand( (double) microtime() * 1000000 ); + $salt = mhash_keygen_s2k( MHASH_SHA1, $passwordClear, substr( pack( 'h*', md5( mt_rand() ) ), 0, 8 ), 4 ); + $cryptedPassword = '{SSHA}'.base64_encode( mhash( MHASH_SHA1, $passwordClear.$salt ).$salt ); + } else { + return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes. + } + break; + + case 'smd5': + if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) { + mt_srand( (double) microtime() * 1000000 ); + $salt = mhash_keygen_s2k( MHASH_MD5, $passwordClear, substr( pack( 'h*', md5( mt_rand() ) ), 0, 8 ), 4 ); + $cryptedPassword = '{SMD5}'.base64_encode( mhash( MHASH_MD5, $passwordClear.$salt ).$salt ); + } else { + return FALSE; //Your PHP install does not have the mhash() function. Cannot do SHA hashes. + } + break; + + case 'samba': + if (function_exists('hash')) { + $cryptedPassword = hash('md4', rcube_charset_convert($passwordClear, RCMAIL_CHARSET, 'UTF-16LE')); + } else { + /* Your PHP install does not have the hash() function */ + return false; + } + break; + + case 'clear': + default: + $cryptedPassword = $passwordClear; + } + + return $cryptedPassword; +} + +/** + * Code originaly from the phpLDAPadmin development team + * http://phpldapadmin.sourceforge.net/ + * + * Used to generate a random salt for crypt-style passwords. Salt strings are used + * to make pre-built hash cracking dictionaries difficult to use as the hash algorithm uses + * not only the user's password but also a randomly generated string. The string is + * stored as the first N characters of the hash for reference of hashing algorithms later. + * + * --- added 20021125 by bayu irawan <bayuir@divnet.telkom.co.id> --- + * --- ammended 20030625 by S C Rigler <srigler@houston.rr.com> --- + * + * @param int $length The length of the salt string to generate. + * @return string The generated salt string. + */ +function randomSalt( $length ) +{ + $possible = '0123456789'. + 'abcdefghijklmnopqrstuvwxyz'. + 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. + './'; + $str = ''; +// mt_srand((double)microtime() * 1000000); + + 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 new file mode 100644 index 000000000..482b7e56f --- /dev/null +++ b/plugins/password/drivers/ldap_simple.php @@ -0,0 +1,270 @@ +<?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 1.0 (2010-07-31) + * @author Wout Decre <wout@canodus.be> + */ +function password_save($curpass, $passwd) +{ + $rcmail = rcmail::get_instance(); + + // Connect + if (!$ds = ldap_connect($rcmail->config->get('password_ldap_host'), $rcmail->config->get('password_ldap_port'))) { + ldap_unbind($ds); + return PASSWORD_CONNECT_ERROR; + } + + // Set protocol version + if (!ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $rcmail->config->get('password_ldap_version'))) { + ldap_unbind($ds); + return PASSWORD_CONNECT_ERROR; + } + + // Start TLS + if ($rcmail->config->get('password_ldap_starttls')) { + if (!ldap_start_tls($ds)) { + ldap_unbind($ds); + return PASSWORD_CONNECT_ERROR; + } + } + + // Build user DN + if ($user_dn = $rcmail->config->get('password_ldap_userDN_mask')) { + $user_dn = ldap_simple_substitute_vars($user_dn); + } else { + $user_dn = ldap_simple_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; + } + + + $crypted_pass = ldap_simple_hash_password($passwd, $rcmail->config->get('password_ldap_encodage')); + $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'); + + // 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 = ldap_simple_hash_password($passwd, 'samba'))) { + return PASSWORD_CRYPT_ERROR; + } + + // Bind + if (!ldap_bind($ds, $binddn, $bindpw)) { + ldap_unbind($ds); + return PASSWORD_CONNECT_ERROR; + } + + $entree[$pwattr] = $crypted_pass; + + // Update PasswordLastChange Attribute if desired + if ($lchattr) { + $entree[$lchattr] = (int)(time() / 86400); + } + + // Update Samba password + if ($smbpwattr) { + $entree[$smbpwattr] = $samba_pass; + } + + // Update Samba password last change + if ($smblchattr) { + $entree[$smblchattr] = time(); + } + + if (!ldap_modify($ds, $user_dn, $entree)) { + ldap_unbind($ds); + return PASSWORD_CONNECT_ERROR; + } + + // 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 ldap_simple_search_userdn($rcmail, $ds) +{ + /* Bind */ + if (!ldap_bind($ds, $rcmail->config->get('password_ldap_searchDN'), $rcmail->config->get('password_ldap_searchPW'))) { + return false; + } + + /* Search for the DN */ + if (!$sr = ldap_search($ds, $rcmail->config->get('password_ldap_search_base'), ldap_simple_substitute_vars($rcmail->config->get('password_ldap_search_filter')))) { + return false; + } + + /* If no or more entries were found, return false */ + if (ldap_count_entries($ds, $sr) != 1) { + return false; + } + + return ldap_get_dn($ds, ldap_first_entry($ds, $sr)); +} + +/** + * Substitute %login, %name, %domain, %dc in $str + * See plugin config for details + */ +function ldap_simple_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 + */ +function ldap_simple_hash_password($password_clear, $encodage_type) +{ + $encodage_type = strtolower($encodage_type); + switch ($encodage_type) { + case 'crypt': + $crypted_password = '{CRYPT}' . crypt($password_clear, ldap_simple_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, '_' . ldap_simple_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$' . ldap_simple_random_salt(9)); + break; + case 'blowfish': + if (!defined('CRYPT_BLOWFISH') || CRYPT_BLOWFISH == 0) { + /* Your system crypt library does not support blowfish encryption */ + return false; + } + /* Hardcoded to second blowfish version and set number of rounds */ + $crypted_password = '{CRYPT}' . crypt($password_clear, '$2a$12$' . ldap_simple_random_salt(13)); + 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('mhash')) { + $crypted_password = '{SHA}' . base64_encode(mhash(MHASH_SHA1, $password_clear)); + } else { + /* Your PHP install does not have the mhash() function */ + return false; + } + break; + case 'ssha': + if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) { + mt_srand((double) microtime() * 1000000 ); + $salt = mhash_keygen_s2k(MHASH_SHA1, $password_clear, substr(pack('h*', md5(mt_rand())), 0, 8), 4); + $crypted_password = '{SSHA}' . base64_encode(mhash(MHASH_SHA1, $password_clear . $salt) . $salt); + } else { + /* Your PHP install does not have the mhash() function */ + return false; + } + break; + case 'smd5': + if (function_exists('mhash') && function_exists('mhash_keygen_s2k')) { + mt_srand((double) microtime() * 1000000 ); + $salt = mhash_keygen_s2k(MHASH_MD5, $password_clear, substr(pack('h*', md5(mt_rand())), 0, 8), 4); + $crypted_password = '{SMD5}' . base64_encode(mhash(MHASH_MD5, $password_clear . $salt) . $salt); + } else { + /* Your PHP install does not have the mhash() function */ + return false; + } + break; + case 'samba': + if (function_exists('hash')) { + $crypted_password = hash('md4', rcube_charset_convert($password_clear, RCMAIL_CHARSET, 'UTF-16LE')); + } else { + /* Your PHP install does not have the hash() function */ + return false; + } + 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 + */ +function ldap_simple_random_salt($length) +{ + $possible = '0123456789' . 'abcdefghijklmnopqrstuvwxyz' . 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' . './'; + $str = ''; + // mt_srand((double)microtime() * 1000000); + while (strlen($str) < $length) { + $str .= substr($possible, (rand() % strlen($possible)), 1); + } + + return $str; +} diff --git a/plugins/password/drivers/pam.php b/plugins/password/drivers/pam.php new file mode 100644 index 000000000..e9363cc5a --- /dev/null +++ b/plugins/password/drivers/pam.php @@ -0,0 +1,41 @@ +<?php + +/** + * PAM Password Driver + * + * @version 1.0 + * @author Aleksander Machniak + */ + +function password_save($currpass, $newpass) +{ + $user = $_SESSION['username']; + + if (extension_loaded('pam')) { + if (pam_auth($user, $currpass, $error, false)) { + if (pam_chpass($user, $currpass, $newpass)) { + return PASSWORD_SUCCESS; + } + } + else { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: PAM authentication failed for user $user: $error" + ), true, false); + } + } + else { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: PECL-PAM module not loaded" + ), true, false); + } + + return PASSWORD_ERROR; +} + +?> diff --git a/plugins/password/drivers/poppassd.php b/plugins/password/drivers/poppassd.php new file mode 100644 index 000000000..fc105de47 --- /dev/null +++ b/plugins/password/drivers/poppassd.php @@ -0,0 +1,64 @@ +<?php + +/** + * Poppassd Password Driver + * + * Driver to change passwords via Poppassd/Courierpassd + * + * @version 1.1 + * @author Philip Weir + * + */ + +function format_error_result($code, $line) +{ + if (preg_match('/^\d\d\d\s+(\S.*)\s*$/', $line, $matches)) { + return array('code' => $code, 'message' => $matches[1]); + } else { + return $code; + } +} + +function password_save($curpass, $passwd) +{ + $rcmail = rcmail::get_instance(); +// include('Net/Socket.php'); + $poppassd = new Net_Socket(); + + $result = $poppassd->connect($rcmail->config->get('password_pop_host'), $rcmail->config->get('password_pop_port'), null); + if (PEAR::isError($result)) { + return format_error_result(PASSWORD_CONNECT_ERROR, $result->getMessage()); + } + else { + $result = $poppassd->readLine(); + if(!preg_match('/^2\d\d/', $result)) { + $poppassd->disconnect(); + return format_error_result(PASSWORD_ERROR, $result); + } + else { + $poppassd->writeLine("user ". $_SESSION['username']); + $result = $poppassd->readLine(); + if(!preg_match('/^[23]\d\d/', $result) ) { + $poppassd->disconnect(); + return format_error_result(PASSWORD_CONNECT_ERROR, $result); + } + else { + $poppassd->writeLine("pass ". $curpass); + $result = $poppassd->readLine(); + if(!preg_match('/^[23]\d\d/', $result) ) { + $poppassd->disconnect(); + return format_error_result(PASSWORD_ERROR, $result); + } + else { + $poppassd->writeLine("newpass ". $passwd); + $result = $poppassd->readLine(); + $poppassd->disconnect(); + if (!preg_match('/^2\d\d/', $result)) + return format_error_result(PASSWORD_ERROR, $result); + else + return PASSWORD_SUCCESS; + } + } + } + } +} diff --git a/plugins/password/drivers/sasl.php b/plugins/password/drivers/sasl.php new file mode 100644 index 000000000..f8ac5c606 --- /dev/null +++ b/plugins/password/drivers/sasl.php @@ -0,0 +1,44 @@ +<?php + +/** + * SASL Password Driver + * + * Driver that adds functionality to change the users Cyrus/SASL password. + * The code is derrived from the Squirrelmail "Change SASL Password" Plugin + * by Galen Johnson. + * + * It only works with saslpasswd2 on the same host where Roundcube runs + * and requires shell access and gcc in order to compile the binary. + * + * For installation instructions please read the README file. + * + * @version 1.0 + * @author Thomas Bruederli + */ + +function password_save($currpass, $newpass) +{ + $curdir = realpath(dirname(__FILE__)); + $username = escapeshellcmd($_SESSION['username']); + $args = rcmail::get_instance()->config->get('password_saslpasswd_args', ''); + + if ($fh = popen("$curdir/chgsaslpasswd -p $args $username", 'w')) { + fwrite($fh, $newpass."\n"); + $code = pclose($fh); + + if ($code == 0) + return PASSWORD_SUCCESS; + } + else { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: Unable to execute $curdir/chgsaslpasswd" + ), true, false); + } + + return PASSWORD_ERROR; +} + +?> diff --git a/plugins/password/drivers/sql.php b/plugins/password/drivers/sql.php new file mode 100644 index 000000000..9ea33df2f --- /dev/null +++ b/plugins/password/drivers/sql.php @@ -0,0 +1,152 @@ +<?php + +/** + * SQL Password Driver + * + * Driver for passwords stored in SQL database + * + * @version 1.3 + * @author Aleksander 'A.L.E.C' Machniak <alec@alec.pl> + * + */ + +function password_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')) { + // #1486067: enable new_link option + if (is_array($dsn) && empty($dsn['new_link'])) + $dsn['new_link'] = true; + else if (!is_array($dsn) && !preg_match('/\?new_link=true/', $dsn)) + $dsn .= '?new_link=true'; + + $db = new rcube_mdb2($dsn, '', FALSE); + $db->set_debug((bool)$rcmail->config->get('sql_debug')); + $db->db_connect('w'); + } else { + $db = $rcmail->get_dbh(); + } + + if ($err = $db->is_error()) + return PASSWORD_ERROR; + + // crypted password + if (strpos($sql, '%c') !== FALSE) { + $salt = ''; + if (CRYPT_MD5) { + $len = rand(3, CRYPT_SALT_LENGTH); + } else if (CRYPT_STD_DES) { + $len = 2; + } else { + return PASSWORD_CRYPT_ERROR; + } + for ($i = 0; $i < $len ; $i++) { + $salt .= chr(rand(ord('.'), ord('z'))); + } + $sql = str_replace('%c', $db->quote(crypt($passwd, CRYPT_MD5 ? '$1$'.$salt.'$' : $salt)), $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'; + + // 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 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); + } + + // hashed passwords + if (preg_match('/%[n|q]/', $sql)) { + + if (!extension_loaded('hash')) { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: 'hash' extension not loaded!" + ), true, false); + + return PASSWORD_ERROR; + } + + if (!($hash_algo = strtolower($rcmail->config->get('password_hash_algorithm')))) + $hash_algo = 'sha1'; + + $hash_passwd = hash($hash_algo, $passwd); + $hash_curpass = hash($hash_algo, $curpass); + + if ($rcmail->config->get('password_hash_base64')) { + $hash_passwd = base64_encode(pack('H*', $hash_passwd)); + $hash_curpass = base64_encode(pack('H*', $hash_curpass)); + } + + $sql = str_replace('%n', $db->quote($hash_passwd, 'text'), $sql); + $sql = str_replace('%q', $db->quote($hash_curpass, '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; + } + } + } + + // at least we should always have the local part + $sql = str_replace('%l', $db->quote($rcmail->user->get_username('local'), 'text'), $sql); + $sql = str_replace('%d', $db->quote($rcmail->user->get_username('domain'), 'text'), $sql); + $sql = str_replace('%u', $db->quote($_SESSION['username'],'text'), $sql); + $sql = str_replace('%h', $db->quote($_SESSION['imap_host'],'text'), $sql); + + $res = $db->query($sql, $sql_vars); + + if (!$db->is_error()) { + if (strtolower(substr(trim($query),0,6))=='select') { + if ($result = $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/drivers/virtualmin.php b/plugins/password/drivers/virtualmin.php new file mode 100644 index 000000000..78ef4e7c3 --- /dev/null +++ b/plugins/password/drivers/virtualmin.php @@ -0,0 +1,75 @@ +<?php + +/** + * Virtualmin Password Driver + * + * Driver that adds functionality to change the users Virtualmin password. + * The code is derrived from the Squirrelmail "Change Cyrus/SASL Password" Plugin + * by Thomas Bruederli. + * + * It only works with virtualmin on the same host where Roundcube runs + * and requires shell access and gcc in order to compile the binary. + * + * @version 2.0 + * @author Martijn de Munnik + */ + +function password_save($currpass, $newpass) +{ + $rcmail = rcmail::get_instance(); + + $format = $rcmail->config->get('password_virtualmin_format', 0); + $username = $_SESSION['username']; + + switch ($format) { + case 1: // username%domain + $domain = substr(strrchr($username, "%"), 1); + break; + case 2: // username.domain (could be bogus) + $pieces = explode(".", $username); + $domain = $pieces[count($pieces)-2]. "." . end($pieces); + break; + case 3: // domain.username (could be bogus) + $pieces = explode(".", $username); + $domain = $pieces[0]. "." . $pieces[1]; + break; + case 4: // username-domain + $domain = substr(strrchr($username, "-"), 1); + break; + case 5: // domain-username + $domain = str_replace(strrchr($username, "-"), "", $username); + break; + case 6: // username_domain + $domain = substr(strrchr($username, "_"), 1); + break; + case 7: // domain_username + $pieces = explode("_", $username); + $domain = $pieces[0]; + break; + default: // username@domain + $domain = substr(strrchr($username, "@"), 1); + } + + $username = escapeshellcmd($username); + $domain = escapeshellcmd($domain); + $newpass = escapeshellcmd($newpass); + $curdir = realpath(dirname(__FILE__)); + + exec("$curdir/chgvirtualminpasswd modify-user --domain $domain --user $username --pass $newpass", $output, $returnvalue); + + if ($returnvalue == 0) { + return PASSWORD_SUCCESS; + } + else { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: Unable to execute $curdir/chgvirtualminpasswd" + ), true, false); + } + + return PASSWORD_ERROR; +} + +?> diff --git a/plugins/password/drivers/vpopmaild.php b/plugins/password/drivers/vpopmaild.php new file mode 100644 index 000000000..b6fb39343 --- /dev/null +++ b/plugins/password/drivers/vpopmaild.php @@ -0,0 +1,51 @@ +<?php + +/** + * vpopmail Password Driver + * + * Driver to change passwords via vpopmaild + * + * @version 1.1 + * @author Johannes Hessellund + * + */ + +function password_save($curpass, $passwd) +{ + $rcmail = rcmail::get_instance(); +// include('Net/Socket.php'); + $vpopmaild = new Net_Socket(); + + if (PEAR::isError($vpopmaild->connect($rcmail->config->get('password_vpopmaild_host'), + $rcmail->config->get('password_vpopmaild_port'), null))) { + return PASSWORD_CONNECT_ERROR; + } + + $result = $vpopmaild->readLine(); + if(!preg_match('/^\+OK/', $result)) { + $vpopmaild->disconnect(); + return PASSWORD_CONNECT_ERROR; + } + + $vpopmaild->writeLine("slogin ". $_SESSION['username'] . " " . $curpass); + $result = $vpopmaild->readLine(); + if(!preg_match('/^\+OK/', $result) ) { + $vpopmaild->writeLine("quit"); + $vpopmaild->disconnect(); + return PASSWORD_ERROR; + } + + $vpopmaild->writeLine("mod_user ". $_SESSION['username']); + $vpopmaild->writeLine("clear_text_password ". $passwd); + $vpopmaild->writeLine("."); + $result = $vpopmaild->readLine(); + $vpopmaild->writeLine("quit"); + $vpopmaild->disconnect(); + + if (!preg_match('/^\+OK/', $result)) + return PASSWORD_ERROR; + + return PASSWORD_SUCCESS; +} + +?> diff --git a/plugins/password/drivers/ximss.php b/plugins/password/drivers/ximss.php new file mode 100644 index 000000000..94aba1874 --- /dev/null +++ b/plugins/password/drivers/ximss.php @@ -0,0 +1,81 @@ +<?php +/** + * Communigate driver for the Password Plugin for Roundcube + * + * Tested with Communigate Pro 5.1.2 + * + * Configuration options: + * password_ximss_host - Host name of Communigate server + * password_ximss_port - XIMSS port on Communigate server + * + * + * References: + * http://www.communigate.com/WebGuide/XMLAPI.html + * + * @version 1 + * @author Erik Meitner <erik wanderings.us> + */ + +function password_save($pass, $newpass) +{ + + $rcmail = rcmail::get_instance(); + + $sock = stream_socket_client("tcp://".$rcmail->config->get('password_ximss_host').":".$rcmail->config->get('password_ximss_port'), $errno, $errstr, 30) ; + if( $sock === FALSE ) + { + return PASSWORD_CONNECT_ERROR; + } + + // send all requests at once(pipelined) + fwrite( $sock, '<login id="A001" authData="'.$_SESSION['username'].'" password="'.$pass.'" />'."\0"); + fwrite( $sock, '<passwordModify id="A002" oldPassword="'.$pass.'" newPassword="'.$newpass.'" />'."\0"); + fwrite( $sock, '<bye id="A003" />'."\0"); + + //example responses + // <session id="A001" urlID="4815-vN2Txjkggy7gjHRD10jw" userName="user@example.com"/>\0 + // <response id="A001"/>\0 + // <response id="A002"/>\0 + // <response id="A003"/>\0 + // or an error: + // <response id="A001" errorText="incorrect password or account name" errorNum="515"/>\0 + + $responseblob = ''; + while (!feof($sock)) { + $responseblob .= fgets($sock, 1024); + } + + fclose($sock); + + foreach( explode( "\0",$responseblob) as $response ) + { + $resp = simplexml_load_string("<xml>".$response."</xml>"); + + if( $resp->response[0]['id'] == 'A001' ) + { + if( isset( $resp->response[0]['errorNum'] ) ) + { + return PASSWORD_CONNECT_ERROR; + } + } + else if( $resp->response[0]['id'] == 'A002' ) + { + if( isset( $resp->response[0]['errorNum'] )) + { + return PASSWORD_ERROR; + } + } + else if( $resp->response[0]['id'] == 'A003' ) + { + if( isset($resp->response[0]['errorNum'] )) + { + //There was a problem during logout(This is probably harmless) + } + } + } //foreach + + return PASSWORD_SUCCESS; + +} + +?>
\ No newline at end of file diff --git a/plugins/password/drivers/xmail.php b/plugins/password/drivers/xmail.php new file mode 100644 index 000000000..c7f426158 --- /dev/null +++ b/plugins/password/drivers/xmail.php @@ -0,0 +1,101 @@ +<?php +/** + * XMail Password Driver + * + * Driver for XMail password + * + * @version 1.0 + * @author Helio Cavichiolo Jr <helio@hcsistemas.com.br> + * + * Setup xmail_host, xmail_user, xmail_pass and xmail_port into + * config.inc.php of password plugin as follows: + * + * $rcmail_config['xmail_host'] = 'localhost'; + * $rcmail_config['xmail_user'] = 'YourXmailControlUser'; + * $rcmail_config['xmail_pass'] = 'YourXmailControlPass'; + * $rcmail_config['xmail_port'] = 6017; + * + */ + +function password_save($currpass, $newpass) +{ + $rcmail = rcmail::get_instance(); + list($user,$domain) = explode('@', $_SESSION['username']); + + $xmail = new XMail; + + $xmail->hostname = $rcmail->config->get('xmail_host'); + $xmail->username = $rcmail->config->get('xmail_user'); + $xmail->password = $rcmail->config->get('xmail_pass'); + $xmail->port = $rcmail->config->get('xmail_port'); + + if (!$xmail->connect()) { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: Unable to connect to mail server" + ), true, false); + return PASSWORD_CONNECT_ERROR; + } else if (!$xmail->send("userpasswd\t".$domain."\t".$user."\t".$newpass."\n")) { + $xmail->close(); + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: Unable to change password" + ), true, false); + return PASSWORD_ERROR; + } else { + $xmail->close(); + return PASSWORD_SUCCESS; + } +} + +class XMail { + var $socket; + var $hostname = 'localhost'; + var $username = 'xmail'; + var $password = ''; + var $port = 6017; + + function send($msg) + { + socket_write($this->socket,$msg); + if (substr($in = socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { + return false; + } + return true; + } + + function connect() + { + $this->socket = socket_create(AF_INET, SOCK_STREAM, 0); + if ($this->socket < 0) + return false; + + $result = socket_connect($this->socket, $this->hostname, $this->port); + if ($result < 0) { + socket_close($this->socket); + return false; + } + + if (substr($in = socket_read($this->socket, 512, PHP_BINARY_READ),0,1) != "+") { + socket_close($this->socket); + return false; + } + + if (!$this->send("$this->username\t$this->password\n")) { + socket_close($this->socket); + return false; + } + return true; + } + + function close() + { + $this->send("quit\n"); + socket_close($this->socket); + } +} + diff --git a/plugins/password/localization/az_AZ.inc b/plugins/password/localization/az_AZ.inc new file mode 100644 index 000000000..62df01ba8 --- /dev/null +++ b/plugins/password/localization/az_AZ.inc @@ -0,0 +1,24 @@ +<?php + +/* Azerbaijani translate for password plugin */ +/* Translated by Nadir Aliyev, nadir at ultel dot net */ + +$labels = array(); +$labels['changepasswd'] = 'Şifrəni dəyiş'; +$labels['curpasswd'] = 'Hal-hazırki şifrə:'; +$labels['newpasswd'] = 'Yeni şifrə:'; +$labels['confpasswd'] = 'Yeni şifrə: (təkrar)'; + +$messages = array(); +$messages['nopassword'] = 'Yeni şifrəni daxil edin.'; +$messages['nocurpassword'] = 'Hal-hazırda istifadə etdiyiniz şifrəni daxil edin.'; +$messages['passwordincorrect'] = 'Yalnış şifrə daxil etdiniz.'; +$messages['passwordinconsistency'] = 'Yeni daxil etdiyiniz şifrələr bir-birinə uyğun deyildir.'; +$messages['crypterror'] = 'Yeni şifrənin saxlanılması mümkün olmadı. Şifrələmə metodu tapılmadı.'; +$messages['connecterror'] = 'Yeni şifrənin saxlanılması mümkün olmadı. Qoşulma səhvi.'; +$messages['internalerror'] = 'Yeni şifrənin saxlanılması mümkün olmadı.'; +$messages['passwordshort'] = 'Yeni şifrə $length simvoldan uzun olmalıdır.'; +$messages['passwordweak'] = 'Şifrədə heç olmasa minimum bir rəqəm və simvol olmalıdır.'; +$messages['passwordforbidden'] = 'Şifrədə icazə verilməyən simvollar vardır.'; + +?> diff --git a/plugins/password/localization/bg_BG.inc b/plugins/password/localization/bg_BG.inc new file mode 100644 index 000000000..b4576a0dc --- /dev/null +++ b/plugins/password/localization/bg_BG.inc @@ -0,0 +1,18 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Смяна на парола'; +$labels['curpasswd'] = 'Текуща парола:'; +$labels['newpasswd'] = 'Нова парола:'; +$labels['confpasswd'] = 'Повторете:'; + +$messages = array(); +$messages['nopassword'] = 'Моля въведете нова парола.'; +$messages['nocurpassword'] = 'Моля въведете текущата .'; +$messages['passwordincorrect'] = 'Невалидна текуща парола.'; +$messages['passwordinconsistency'] = 'Паролите не съвпадат, опитайте пак.'; +$messages['crypterror'] = 'Паролата не може да бъде сменена. Грешка в криптирането.'; +$messages['connecterror'] = 'Паролата не може да бъде сменена. Грешка в свързването.'; +$messages['internalerror'] = 'Паролата не може да бъде сменена.'; + +?> diff --git a/plugins/password/localization/ca_ES.inc b/plugins/password/localization/ca_ES.inc new file mode 100644 index 000000000..18c10c80e --- /dev/null +++ b/plugins/password/localization/ca_ES.inc @@ -0,0 +1,20 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Canviar contrasenya'; +$labels['curpasswd'] = 'Contrasenya actual:'; +$labels['newpasswd'] = 'Nova contrasenya:'; +$labels['confpasswd'] = 'Confirmar nova contrasenya:'; + +$messages = array(); +$messages['nopassword'] = 'Si us plau, introdueix la nova contrasenya.'; +$messages['nocurpassword'] = 'Si us plau, introdueix la contrasenya actual.'; +$messages['passwordincorrect'] = 'Contrasenya actual incorrecte.'; +$messages['passwordinconsistency'] = 'La contrasenya nova no coincideix!.'; +$messages['crypterror'] = 'No es pot desar la nova contrasenya. No existeix la funció d\'encriptació.'; +$messages['connecterror'] = 'No es pot desar la nova contrasenya. Error de connexió.'; +$messages['internalerror'] = 'No es pot desar la nova contrasenya.'; +$messages['passwordshort'] = 'La nova contrasenya ha de tenir com a mínim $length caràcters de llarg.'; +$messages['passwordweak'] = 'La nova contrasenya ha d\'incloure com a mínim un nombre i un caràcter de puntuació.'; + +?> diff --git a/plugins/password/localization/cs_CZ.inc b/plugins/password/localization/cs_CZ.inc new file mode 100644 index 000000000..b4b7b29f9 --- /dev/null +++ b/plugins/password/localization/cs_CZ.inc @@ -0,0 +1,30 @@ +<?php + +/** + * Czech translation for Roundcube password plugin + * + * @version 1.0 (2009-08-29) + * @author Milan Kozak <hodza@hodza.net> + * @author Tomáš Šafařík <safarik@server.cz> + * + */ + +$labels = array(); +$labels['changepasswd'] = 'Změna hesla'; +$labels['curpasswd'] = 'Aktuální heslo:'; +$labels['newpasswd'] = 'Nové heslo:'; +$labels['confpasswd'] = 'Nové heslo (pro kontrolu):'; + +$messages = array(); +$messages['nopassword'] = 'Prosím zadejte nové heslo.'; +$messages['nocurpassword'] = 'Prosím zadejte aktuální heslo.'; +$messages['passwordincorrect'] = 'Zadané aktuální heslo není správné.'; +$messages['passwordinconsistency'] = 'Zadaná hesla se neshodují. Prosím zkuste to znovu.'; +$messages['crypterror'] = 'Heslo se nepodařilo uložit. Chybí šifrovací funkce.'; +$messages['connecterror'] = 'Heslo se nepodařilo uložit. Problém s připojením.'; +$messages['internalerror'] = 'Heslo se nepodařilo uložit.'; +$messages['passwordshort'] = 'Heslo musí mít alespoň $length znaků.'; +$messages['passwordweak'] = 'Heslo musí obsahovat alespoň jedno číslo a jedno interpuknční znaménko.'; +$messages['passwordforbidden'] = 'Heslo obsahuje nepovolené znaky.'; + +?> diff --git a/plugins/password/localization/da_DK.inc b/plugins/password/localization/da_DK.inc new file mode 100644 index 000000000..5d1d0c9cc --- /dev/null +++ b/plugins/password/localization/da_DK.inc @@ -0,0 +1,18 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Skift adgangskode'; +$labels['curpasswd'] = 'Nuværende adgangskode:'; +$labels['newpasswd'] = 'Ny adgangskode:'; +$labels['confpasswd'] = 'Bekræft ny adgangskode:'; + +$messages = array(); +$messages['nopassword'] = 'Indtast venligst en ny adgangskode.'; +$messages['nocurpassword'] = 'Indtast venligst nyværende adgangskode.'; +$messages['passwordincorrect'] = 'Nyværende adgangskode er forkert.'; +$messages['passwordinconsistency'] = 'Adgangskoderne er ikke ens, prøv igen.'; +$messages['crypterror'] = 'Kunne ikke gemme den nye adgangskode. Krypteringsfunktion mangler.'; +$messages['connecterror'] = 'Kunne ikke gemme den nye adgangskode. Fejl ved forbindelsen.'; +$messages['internalerror'] = 'Kunne ikke gemme den nye adgangskode.'; + +?> diff --git a/plugins/password/localization/de_CH.inc b/plugins/password/localization/de_CH.inc new file mode 100644 index 000000000..a28990d67 --- /dev/null +++ b/plugins/password/localization/de_CH.inc @@ -0,0 +1,19 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Passwort ändern'; +$labels['curpasswd'] = 'Aktuelles Passwort'; +$labels['newpasswd'] = 'Neues Passwort'; +$labels['confpasswd'] = 'Passwort Wiederholung'; + +$messages = array(); +$messages['nopassword'] = "Bitte geben Sie ein neues Passwort ein"; +$messages['nocurpassword'] = "Bitte geben Sie Ihr aktuelles Passwort an"; +$messages['passwordincorrect'] = "Das aktuelle Passwort ist nicht korrekt"; +$messages['passwordinconsistency'] = "Das neue Passwort und dessen Wiederholung stimmen nicht überein"; +$messages['crypterror'] = "Neues Passwort nicht gespeichert: Verschlüsselungsfunktion fehlt"; +$messages['connecterror'] = "Neues Passwort nicht gespeichert: Verbindungsfehler"; +$messages['internalerror'] = "Neues Passwort nicht gespeichert"; + + +?>
\ No newline at end of file diff --git a/plugins/password/localization/de_DE.inc b/plugins/password/localization/de_DE.inc new file mode 100644 index 000000000..a28990d67 --- /dev/null +++ b/plugins/password/localization/de_DE.inc @@ -0,0 +1,19 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Passwort ändern'; +$labels['curpasswd'] = 'Aktuelles Passwort'; +$labels['newpasswd'] = 'Neues Passwort'; +$labels['confpasswd'] = 'Passwort Wiederholung'; + +$messages = array(); +$messages['nopassword'] = "Bitte geben Sie ein neues Passwort ein"; +$messages['nocurpassword'] = "Bitte geben Sie Ihr aktuelles Passwort an"; +$messages['passwordincorrect'] = "Das aktuelle Passwort ist nicht korrekt"; +$messages['passwordinconsistency'] = "Das neue Passwort und dessen Wiederholung stimmen nicht überein"; +$messages['crypterror'] = "Neues Passwort nicht gespeichert: Verschlüsselungsfunktion fehlt"; +$messages['connecterror'] = "Neues Passwort nicht gespeichert: Verbindungsfehler"; +$messages['internalerror'] = "Neues Passwort nicht gespeichert"; + + +?>
\ No newline at end of file diff --git a/plugins/password/localization/en_US.inc b/plugins/password/localization/en_US.inc new file mode 100644 index 000000000..1ae2158b0 --- /dev/null +++ b/plugins/password/localization/en_US.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Change Password'; +$labels['curpasswd'] = 'Current Password:'; +$labels['newpasswd'] = 'New Password:'; +$labels['confpasswd'] = 'Confirm New Password:'; + +$messages = array(); +$messages['nopassword'] = 'Please input new password.'; +$messages['nocurpassword'] = 'Please input current password.'; +$messages['passwordincorrect'] = 'Current password incorrect.'; +$messages['passwordinconsistency'] = 'Passwords do not match, please try again.'; +$messages['crypterror'] = 'Could not save new password. Encryption function missing.'; +$messages['connecterror'] = 'Could not save new password. Connection error.'; +$messages['internalerror'] = 'Could not save new password.'; +$messages['passwordshort'] = 'Password must be at least $length characters long.'; +$messages['passwordweak'] = 'Password must include at least one number and one punctuation character.'; +$messages['passwordforbidden'] = 'Password contains forbidden characters.'; + +?> diff --git a/plugins/password/localization/es_AR.inc b/plugins/password/localization/es_AR.inc new file mode 100644 index 000000000..40c74e673 --- /dev/null +++ b/plugins/password/localization/es_AR.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Cambiar Contraseña'; +$labels['curpasswd'] = 'Contraseña Actual:'; +$labels['newpasswd'] = 'Contraseña Nueva:'; +$labels['confpasswd'] = 'Confirmar Contraseña:'; + +$messages = array(); +$messages['nopassword'] = 'Por favor introduce una nueva contraseña.'; +$messages['nocurpassword'] = 'Por favor introduce la contraseña actual.'; +$messages['passwordincorrect'] = 'Contraseña actual incorrecta.'; +$messages['passwordinconsistency'] = 'Las contraseñas no coinciden, por favor inténtalo de nuevo.'; +$messages['crypterror'] = 'No se pudo guardar la contraseña nueva. Falta la función de cifrado.'; +$messages['connecterror'] = 'No se pudo guardar la contraseña nueva. Error de conexión'; +$messages['internalerror'] = 'No se pudo guardar la contraseña nueva.'; +$messages['passwordshort'] = 'Tu contraseña debe tener una longitud mínima de $length.'; +$messages['passwordweak'] = 'Tu nueva contraseña debe incluir al menos un número y un signo de puntuación.'; +$messages['passwordforbidden'] = 'La contraseña contiene caracteres inválidos.'; + +?> diff --git a/plugins/password/localization/es_ES.inc b/plugins/password/localization/es_ES.inc new file mode 100644 index 000000000..32879b4aa --- /dev/null +++ b/plugins/password/localization/es_ES.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Cambiar contraseña'; +$labels['curpasswd'] = 'Contraseña actual:'; +$labels['newpasswd'] = 'Contraseña nueva:'; +$labels['confpasswd'] = 'Confirmar contraseña:'; + +$messages = array(); +$messages['nopassword'] = 'Por favor introduzca una contraseña nueva.'; +$messages['nocurpassword'] = 'Por favor introduzca la contraseña actual.'; +$messages['passwordincorrect'] = 'La contraseña actual es incorrecta.'; +$messages['passwordinconsistency'] = 'Las contraseñas no coinciden. Por favor, inténtelo de nuevo.'; +$messages['crypterror'] = 'No se pudo guardar la contraseña nueva. Falta la función de cifrado.'; +$messages['connecterror'] = 'No se pudo guardar la contraseña nueva. Error de conexión'; +$messages['internalerror'] = 'No se pudo guardar la contraseña nueva.'; +$messages['passwordshort'] = 'La contraseña debe tener por lo menos $length caracteres.'; +$messages['passwordweak'] = 'La contraseña debe incluir al menos un número y un signo de puntuación.'; +$messages['passwordforbidden'] = 'La contraseña introducida contiene caracteres no permitidos.'; + +?> diff --git a/plugins/password/localization/et_EE.inc b/plugins/password/localization/et_EE.inc new file mode 100644 index 000000000..0f351d77b --- /dev/null +++ b/plugins/password/localization/et_EE.inc @@ -0,0 +1,17 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Muuda parooli'; +$labels['curpasswd'] = 'Vana parool:'; +$labels['newpasswd'] = 'Uus parool:'; +$labels['confpasswd'] = 'Uus parool uuesti:'; + +$messages = array(); +$messages['nopassword'] = 'Palun sisesta uus parool.'; +$messages['nocurpassword'] = 'Palun sisesta vana parool.'; +$messages['passwordincorrect'] = 'Vana parool on vale.'; +$messages['passwordinconsistency'] = 'Paroolid ei kattu, palun proovi uuesti.'; +$messages['crypterror'] = 'Serveris ei ole parooli krüpteerimiseks vajalikku funktsiooni.'; +$messages['internalerror'] = 'Uue parooli andmebaasi salvestamine nurjus.'; + +?> diff --git a/plugins/password/localization/fi_FI.inc b/plugins/password/localization/fi_FI.inc new file mode 100644 index 000000000..a2108a524 --- /dev/null +++ b/plugins/password/localization/fi_FI.inc @@ -0,0 +1,22 @@ +<?php + +// Translation by Tapio Salonsaari <take@nerd.fi> + +$labels = array(); +$labels['changepasswd'] = 'Vaihda salasana'; +$labels['curpasswd'] = 'Nykyinen salasana:'; +$labels['newpasswd'] = 'Uusi salasana:'; +$labels['confpasswd'] = 'Uusi salasana uudestaan:'; + +$messages = array(); +$messages['nopassword'] = 'Syötä uusi salasana.'; +$messages['nocurpassword'] = 'Syötä nykyinen salasana.'; +$messages['passwordincorrect'] = 'Syöttämäsi nykyinen salasana on väärin.'; +$messages['passwordinconsistency'] = 'Syöttämäsi salasanat eivät täsmää, yritä uudelleen.'; +$messages['crypterror'] = 'Salasanaa ei voitu vaihtaa. Kryptausfunktio puuttuu.'; +$messages['connecterror'] = 'Salasanaa ei voitu vaihtaa. Yhteysongelma.'; +$messages['internalerror'] = 'Salasanaa ei voitu vaihtaa.'; +$messages['passwordshort'] = 'Salasanan täytyy olla vähintään $length merkkiä pitkä.'; +$messages['passwordweak'] = 'Salasanan täytyy sisältää vähintään yksi numero ja yksi välimerkki.'; + +?> diff --git a/plugins/password/localization/fr_FR.inc b/plugins/password/localization/fr_FR.inc new file mode 100644 index 000000000..8ba37b148 --- /dev/null +++ b/plugins/password/localization/fr_FR.inc @@ -0,0 +1,18 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Changer le mot de passe'; +$labels['curpasswd'] = 'Mot de passe actuel:'; +$labels['newpasswd'] = 'Nouveau mot de passe:'; +$labels['confpasswd'] = 'Confirmez le nouveau mot de passe:'; + +$messages = array(); +$messages['nopassword'] = 'Veuillez saisir le nouveau mot de passe.'; +$messages['nocurpassword'] = 'Veuillez saisir le mot de passe actuel.'; +$messages['passwordincorrect'] = 'Mot de passe actuel incorrect.'; +$messages['passwordinconsistency'] = 'Les nouveaux mots de passe ne correspondent pas, veuillez réessayer.'; +$messages['crypterror'] = 'Impossible d\'enregistrer le nouveau mot de passe. Fonction de cryptage manquante.'; +$messages['connecterror'] = 'Impossible d\'enregistrer le nouveau mot de passe. Erreur de connexion au serveur.'; +$messages['internalerror'] = 'Impossible d\'enregistrer le nouveau mot de passe.'; + +?> diff --git a/plugins/password/localization/gl_ES.inc b/plugins/password/localization/gl_ES.inc new file mode 100644 index 000000000..b7dc7bbee --- /dev/null +++ b/plugins/password/localization/gl_ES.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Cambiar contrasinal'; +$labels['curpasswd'] = 'Contrasinal actual:'; +$labels['newpasswd'] = 'Contrasinal novo:'; +$labels['confpasswd'] = 'Confirmar contrasinal:'; + +$messages = array(); +$messages['nopassword'] = 'Por favor, introduza un contrasinal novo.'; +$messages['nocurpassword'] = 'Por favor, introduza o contrasinal actual.'; +$messages['passwordincorrect'] = 'O contrasinal actual é incorrecto.'; +$messages['passwordinconsistency'] = 'Os contrasinals non coinciden. Por favor, inténteo de novo.'; +$messages['crypterror'] = 'Non foi posible gardar o contrasinal novo. Falta a función de cifrado.'; +$messages['connecterror'] = 'Non foi posible gardar o contrasinal novo. Erro de conexión'; +$messages['internalerror'] = 'Non foi posible gardar o contrasinal novo.'; +$messages['passwordshort'] = 'O contrasinal debe ter polo menos $length caracteres.'; +$messages['passwordweak'] = 'O contrasinal debe incluir polo menos un número e un signo de puntuación.'; +$messages['passwordforbidden'] = 'O contrasinal contén caracteres non permitidos.'; + +?> diff --git a/plugins/password/localization/hr_HR.inc b/plugins/password/localization/hr_HR.inc new file mode 100644 index 000000000..0e35129c0 --- /dev/null +++ b/plugins/password/localization/hr_HR.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Promijeni zaporku'; +$labels['curpasswd'] = 'Važeća zaporka:'; +$labels['newpasswd'] = 'Nova zaporka:'; +$labels['confpasswd'] = 'Potvrda nove zaporke:'; + +$messages = array(); +$messages['nopassword'] = 'Molimo unesite novu zaporku.'; +$messages['nocurpassword'] = 'Molimo unesite trenutnu zaporku.'; +$messages['passwordincorrect'] = 'Trenutna zaporka je nevažeća.'; +$messages['passwordinconsistency'] = 'Zaporke su različite, pokušajte ponovo.'; +$messages['crypterror'] = 'Nemoguće promijeniti zaporku. Nedostaje enkripcijska funkcija.'; +$messages['connecterror'] = 'Nemoguće promijeniti zaporku. Greška prilikom spajanja.'; +$messages['internalerror'] = 'Nemoguće promijeniti zaporku.'; +$messages['passwordshort'] = 'Zaporka mora sadržavati barem $length znakova.'; +$messages['passwordweak'] = 'Zaporka mora sadržavati barem jedanu znamenku i jedan interpunkcijski znak.'; +$messages['passwordforbidden'] = 'Zaporka sadrži nedozvoljene znakove.'; + +?> diff --git a/plugins/password/localization/hu_HU.inc b/plugins/password/localization/hu_HU.inc new file mode 100644 index 000000000..c8c3015a1 --- /dev/null +++ b/plugins/password/localization/hu_HU.inc @@ -0,0 +1,17 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Jelszóváltás'; +$labels['curpasswd'] = 'Jelenlegi jelszó:'; +$labels['newpasswd'] = 'Új jelszó:'; +$labels['confpasswd'] = 'Új jelszó mégegyszer:'; + +$messages = array(); +$messages['nopassword'] = 'Kérjük adja meg az új jelszót.'; +$messages['nocurpassword'] = 'Kérjük adja meg a jelenlegi jelszót.'; +$messages['passwordincorrect'] = 'Érvénytelen a jelenlegi jelszó.'; +$messages['passwordinconsistency'] = 'A két új jelszó nem egyezik.'; +$messages['crypterror'] = 'Hiba történt a kérés feldolgozása során.'; +$messages['internalerror'] = 'Hiba történt a kérés feldolgozása során.'; + +?> diff --git a/plugins/password/localization/it_IT.inc b/plugins/password/localization/it_IT.inc new file mode 100644 index 000000000..13b4885d7 --- /dev/null +++ b/plugins/password/localization/it_IT.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Cambia la Password'; +$labels['curpasswd'] = 'Password corrente:'; +$labels['newpasswd'] = 'Nuova Password:'; +$labels['confpasswd'] = 'Conferma la Nuova Password:'; + +$messages = array(); +$messages['nopassword'] = 'Per favore inserisci la nuova password.'; +$messages['nocurpassword'] = 'Per favore inserisci la password corrente.'; +$messages['passwordincorrect'] = 'Password corrente sbagliata.'; +$messages['passwordinconsistency'] = 'Le password non coincidono, inserirle di nuovo.'; +$messages['crypterror'] = 'Non posso salvare la password, funzione di cifratura assente.'; +$messages['connecterror'] = 'Non posso salvare la password, errore di connessione.'; +$messages['internalerror'] = 'Non posso salvare la password.'; +$messages['passwordshort'] = 'La nuova password deve essere lunga almeno $length caratteri.'; +$messages['passwordweak'] = 'La nuova password deve contenere almeno una cifra e un segno di punteggiatura.'; +$messages['passwordforbidden'] = 'La password scelta contiene dei caratteri non consentiti.'; + +?> diff --git a/plugins/password/localization/ja_JP.inc b/plugins/password/localization/ja_JP.inc new file mode 100644 index 000000000..47cac0430 --- /dev/null +++ b/plugins/password/localization/ja_JP.inc @@ -0,0 +1,23 @@ +<?php + +// EN-Revision: 3891 + +$labels = array(); +$labels['changepasswd'] = 'パスワードの変更'; +$labels['curpasswd'] = '現在のパスワード:'; +$labels['newpasswd'] = '新しいパスワード:'; +$labels['confpasswd'] = '新しいパスワード (確認):'; + +$messages = array(); +$messages['nopassword'] = '新しいパスワードを入力してください。'; +$messages['nocurpassword'] = '現在のパスワードを入力してください。'; +$messages['passwordincorrect'] = '現在のパスワードが間違っています。'; +$messages['passwordinconsistency'] = 'パスワードが一致しません。もう一度やり直してください。'; +$messages['crypterror'] = 'パスワードを保存できませんでした。暗号化関数がみあたりません。'; +$messages['connecterror'] = '新しいパスワードを保存できませんでした。接続エラーです。'; +$messages['internalerror'] = '新しいパスワードを保存できませんでした。'; +$messages['passwordshort'] = 'パスワードは少なくとも $length 文字の長さが必要です。'; +$messages['passwordweak'] = 'パスワードは少なくとも数字を 1 文字と記号が 1 文字含んでなければなりません。'; +$messages['passwordforbidden'] = 'パスワードに禁止された文字が含まれています。'; + +?> diff --git a/plugins/password/localization/lt_LT.inc b/plugins/password/localization/lt_LT.inc new file mode 100644 index 000000000..b4563cc42 --- /dev/null +++ b/plugins/password/localization/lt_LT.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Slaptažodžio keitimas'; +$labels['curpasswd'] = 'Dabartinis slaptažodis:'; +$labels['newpasswd'] = 'Naujasis slaptažodis:'; +$labels['confpasswd'] = 'Pakartokite naująjį slaptažodį:'; + +$messages = array(); +$messages['nopassword'] = 'Prašom įvesti naująjį slaptažodį.'; +$messages['nocurpassword'] = 'Prašom įvesti dabartinį slaptažodį.'; +$messages['passwordincorrect'] = 'Dabartinis slaptažodis neteisingas.'; +$messages['passwordinconsistency'] = 'Slaptažodžiai nesutapo. Bandykite dar kartą.'; +$messages['crypterror'] = 'Nepavyko įrašyti naujojo slaptažodžio. Trūksta šifravimo funkcijos.'; +$messages['connecterror'] = 'Nepavyko įrašyti naujojo slaptažodžio. Prisijungimo klaida.'; +$messages['internalerror'] = 'Nepavyko įrašyti naujojo slaptažodžio.'; +$messages['passwordshort'] = 'Slaptažodis turi būti sudarytas iš bent $length simbolių.'; +$messages['passwordweak'] = 'Slaptažodyje turi būti bent vienas skaitmuo ir vienas skyrybos ženklas.'; +$messages['passwordforbidden'] = 'Slaptažodyje rasta neleistinų simbolių.'; + +?> diff --git a/plugins/password/localization/lv_LV.inc b/plugins/password/localization/lv_LV.inc new file mode 100644 index 000000000..8f5f4c2c2 --- /dev/null +++ b/plugins/password/localization/lv_LV.inc @@ -0,0 +1,20 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Nomainīt paroli'; +$labels['curpasswd'] = 'Pašreizējā parole:'; +$labels['newpasswd'] = 'Jaunā parole:'; +$labels['confpasswd'] = 'Vēlreiz jauno paroli:'; + +$messages = array(); +$messages['nopassword'] = 'Lūdzu, ievadiet jauno paroli.'; +$messages['nocurpassword'] = 'Lūdzu, ievadiet pašreizējo paroli.'; +$messages['passwordincorrect'] = 'Pašreizējā parole nepareiza.'; +$messages['passwordinconsistency'] = 'Paroles nesakrīt. Lūdzu, ievadiet vēlreiz.'; +$messages['crypterror'] = 'Nevarēja saglabāt jauno paroli. Trūkst kriptēšanas funkcija.'; +$messages['connecterror'] = 'Nevarēja saglabāt jauno paroli. Savienojuma kļūda.'; +$messages['internalerror'] = 'Nevarēja saglabāt jauno paroli.'; +$messages['passwordshort'] = 'Jaunajai parolei jābūt vismaz $length simbola garai.'; +$messages['passwordweak'] = 'Jaunajai parolei jāsatur vismaz viens cipars un punktuācijas simbols.'; + +?> diff --git a/plugins/password/localization/nl_NL.inc b/plugins/password/localization/nl_NL.inc new file mode 100644 index 000000000..6d7c401ac --- /dev/null +++ b/plugins/password/localization/nl_NL.inc @@ -0,0 +1,17 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Wijzig Wachtwoord'; +$labels['curpasswd'] = 'Huidig Wachtwoord:'; +$labels['newpasswd'] = 'Nieuw Wachtwoord:'; +$labels['confpasswd'] = 'Bevestig Nieuw Wachtwoord:'; + +$messages = array(); +$messages['nopassword'] = 'Vul een wachtwoord in.'; +$messages['nocurpassword'] = 'vul het huidige wachtwoord in.'; +$messages['passwordincorrect'] = 'Huidig wachtwoord is onjuist.'; +$messages['passwordinconsistency'] = 'Wachtwoorden komen niet overeen, probeer het opnieuw.'; +$messages['crypterror'] = 'De server mist een functie om uw wachtwoord et beveiligen.'; +$messages['internalerror'] = 'Uw wachtwoord kan niet worden opgeslagen.'; + +?> diff --git a/plugins/password/localization/pl_PL.inc b/plugins/password/localization/pl_PL.inc new file mode 100644 index 000000000..687ca9383 --- /dev/null +++ b/plugins/password/localization/pl_PL.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Zmiana hasła'; +$labels['curpasswd'] = 'Aktualne hasło:'; +$labels['newpasswd'] = 'Nowe hasło:'; +$labels['confpasswd'] = 'Potwierdź hasło:'; + +$messages = array(); +$messages['nopassword'] = 'Wprowadź nowe hasło.'; +$messages['nocurpassword'] = 'Wprowadź aktualne hasło.'; +$messages['passwordincorrect'] = 'Błędne aktualne hasło, spróbuj ponownie.'; +$messages['passwordinconsistency'] = 'Hasła nie pasują, spróbuj ponownie.'; +$messages['crypterror'] = 'Nie udało się zapisać nowego hasła. Brak funkcji kodującej.'; +$messages['connecterror'] = 'Nie udało się zapisać nowego hasła. Błąd połączenia.'; +$messages['internalerror'] = 'Nie udało się zapisać nowego hasła.'; +$messages['passwordshort'] = 'Hasło musi posiadać co najmniej $length znaków.'; +$messages['passwordweak'] = 'Hasło musi zawierać co najmniej jedną cyfrę i znak interpunkcyjny.'; +$messages['passwordforbidden'] = 'Hasło zawiera niedozwolone znaki.'; + +?> diff --git a/plugins/password/localization/pt_BR.inc b/plugins/password/localization/pt_BR.inc new file mode 100644 index 000000000..f3626e834 --- /dev/null +++ b/plugins/password/localization/pt_BR.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Alterar senha'; +$labels['curpasswd'] = 'Senha atual:'; +$labels['newpasswd'] = 'Nova senha:'; +$labels['confpasswd'] = 'Confirmar nova senha:'; + +$messages = array(); +$messages['nopassword'] = 'Por favor, informe a nova senha.'; +$messages['nocurpassword'] = 'Por favor, informe a senha atual.'; +$messages['passwordincorrect'] = 'Senha atual incorreta.'; +$messages['passwordinconsistency'] = 'Senhas não combinam, por favor tente novamente.'; +$messages['crypterror'] = 'Não foi possível gravar a nova senha. Função de criptografia ausente.'; +$messages['connecterror'] = 'Não foi possível gravar a nova senha. Erro de conexão.'; +$messages['internalerror'] = 'Não foi possível gravar a nova senha.'; +$messages['passwordshort'] = 'A senha precisa ter ao menos $length caracteres.'; +$messages['passwordweak'] = 'A senha precisa conter ao menos um número e um caractere de pontuação.'; +$messages['passwordforbidden'] = 'A senha contém caracteres proibidos.'; + +?> diff --git a/plugins/password/localization/pt_PT.inc b/plugins/password/localization/pt_PT.inc new file mode 100644 index 000000000..5307ad69f --- /dev/null +++ b/plugins/password/localization/pt_PT.inc @@ -0,0 +1,18 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Alterar password'; +$labels['curpasswd'] = 'Password atual:'; +$labels['newpasswd'] = 'Nova password:'; +$labels['confpasswd'] = 'Confirmar password:'; + +$messages = array(); +$messages['nopassword'] = 'Introduza a nova password.'; +$messages['nocurpassword'] = 'Introduza a password actual.'; +$messages['passwordincorrect'] = 'Password actual errada.'; +$messages['passwordinconsistency'] = 'Password\'s não combinam, tente novamente..'; +$messages['crypterror'] = 'Não foi possível gravar a nova password. Função de criptografica inexistente.'; +$messages['connecterror'] = 'Não foi possível gravar a nova password. Erro de ligação.'; +$messages['internalerror'] = 'Não foi possível gravar a nova password.'; + +?> diff --git a/plugins/password/localization/ru_RU.inc b/plugins/password/localization/ru_RU.inc new file mode 100644 index 000000000..3776b4598 --- /dev/null +++ b/plugins/password/localization/ru_RU.inc @@ -0,0 +1,35 @@ +<?php +/* + ++-----------------------------------------------------------------------+ +| plugins/password/localization/ru_RU.inc | +| | +| Language file of the Roundcube help plugin | +| Copyright (C) 2005-2010, The Roundcube Dev Team | +| Licensed under the GNU GPL | +| | ++-----------------------------------------------------------------------+ +| Author: Sergey Dukachev <iam@dukess.ru> | ++-----------------------------------------------------------------------+ + +*/ + +$labels = array(); +$labels['changepasswd'] = 'Изменить пароль'; +$labels['curpasswd'] = 'Текущий пароль:'; +$labels['newpasswd'] = 'Новый пароль:'; +$labels['confpasswd'] = 'Подтвердите новый пароль:'; + +$messages = array(); +$messages['nopassword'] = 'Пожалуйста, введите новый пароль.'; +$messages['nocurpassword'] = 'Пожалуйста, введите текущий пароль.'; +$messages['passwordincorrect'] = 'Текущий пароль неверен.'; +$messages['passwordinconsistency'] = 'Пароли не совпадают, попробуйте, пожалуйста, ещё.'; +$messages['crypterror'] = 'Не могу сохранить новый пароль. Отсутствует криптографическая функция.'; +$messages['connecterror'] = 'Не могу сохранить новый пароль. Ошибка соединения.'; +$messages['internalerror'] = 'Не могу сохранить новый пароль.'; +$messages['passwordshort'] = 'Пароль должен быть длиной как минимум $length символов.'; +$messages['passwordweak'] = 'Пароль должен включать в себя как минимум одну цифру и один знак пунктуации.'; +$messages['passwordforbidden'] = 'Пароль содержит недопустимые символы.'; + +?> diff --git a/plugins/password/localization/sk_SK.inc b/plugins/password/localization/sk_SK.inc new file mode 100644 index 000000000..6def2f914 --- /dev/null +++ b/plugins/password/localization/sk_SK.inc @@ -0,0 +1,29 @@ +<?php + +/** + * Slovak translation for Roundcube password plugin + * + * @version 1.0 (2010-10-18) + * @author panda <admin@whistler.sk> + * + */ + +$labels = array(); +$labels['changepasswd'] = 'Zmeniť heslo'; +$labels['curpasswd'] = 'Súčasné heslo:'; +$labels['newpasswd'] = 'Nové heslo:'; +$labels['confpasswd'] = 'Potvrď nové heslo:'; + +$messages = array(); +$messages['nopassword'] = 'Prosím zadaj nové heslo.'; +$messages['nocurpassword'] = 'Prosím zadaj súčasné heslo.'; +$messages['passwordincorrect'] = 'Súčasné heslo je nesprávne.'; +$messages['passwordinconsistency'] = 'Heslá nie sú rovnaké, skús znova.'; +$messages['crypterror'] = 'Nemôžem uložiť nové heslo. Chýba šifrovacia funkcia.'; +$messages['connecterror'] = 'Nemôžem uložiť nové heslo. Chyba spojenia.'; +$messages['internalerror'] = 'Nemôžem uložiť nové heslo.'; +$messages['passwordshort'] = 'Heslo musí mať najmenej $length znakov.'; +$messages['passwordweak'] = 'Heslo musí obsahovať aspoň jedno číslo a jedno interpunkčné znamienko.'; +$messages['passwordforbidden'] = 'Heslo obsahuje nepovolené znaky.'; + +?> diff --git a/plugins/password/localization/sl_SI.inc b/plugins/password/localization/sl_SI.inc new file mode 100644 index 000000000..df17583be --- /dev/null +++ b/plugins/password/localization/sl_SI.inc @@ -0,0 +1,18 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Spremeni geslo'; +$labels['curpasswd'] = 'Obstoječe geslo:'; +$labels['newpasswd'] = 'Novo geslo:'; +$labels['confpasswd'] = 'Potrdi novo geslo:'; + +$messages = array(); +$messages['nopassword'] = 'Vnesite novo geslo.'; +$messages['nocurpassword'] = 'Vnesite obstoječe geslo.'; +$messages['passwordincorrect'] = 'Obstoječe geslo ni veljavno.'; +$messages['passwordinconsistency'] = 'Gesli se ne ujemata, poskusite znova.'; +$messages['crypterror'] = 'Novega gesla ni bilo mogoče shraniti. Prišlo je do napake pri šifriranju.'; +$messages['connecterror'] = 'Novega gesla ni bilo mogoče shraniti. Prišlo je do napake v povezavi.'; +$messages['internalerror'] = 'Novega gesla ni bilo mogoče shraniti.'; + +?> diff --git a/plugins/password/localization/sv_SE.inc b/plugins/password/localization/sv_SE.inc new file mode 100644 index 000000000..d649bbd9a --- /dev/null +++ b/plugins/password/localization/sv_SE.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Ändra lösenord'; +$labels['curpasswd'] = 'Nuvarande lösenord:'; +$labels['newpasswd'] = 'Nytt lösenord:'; +$labels['confpasswd'] = 'Bekräfta nytt lösenord:'; + +$messages = array(); +$messages['nopassword'] = 'Vänligen ange nytt lösenord.'; +$messages['nocurpassword'] = 'Vänligen ange nuvarande lösenord.'; +$messages['passwordincorrect'] = 'Felaktigt nuvarande lösenord.'; +$messages['passwordinconsistency'] = 'Nya lösenordet och bekräftelsen överensstämmer inte, försök igen.'; +$messages['crypterror'] = 'Lösenordet kunde inte ändras. Krypteringsfunktionen saknas.'; +$messages['connecterror'] = 'Lösenordet kunde inte ändras. Anslutningen misslyckades.'; +$messages['internalerror'] = 'Lösenordet kunde inte ändras.'; +$messages['passwordshort'] = 'Lösenordet måste vara minst $length tecken långt.'; +$messages['passwordweak'] = 'Lösenordet måste innehålla minst en siffra och ett specialtecken.'; +$messages['passwordforbidden'] = 'Lösenordet innehåller otillåtna tecken.'; + +?>
\ No newline at end of file diff --git a/plugins/password/localization/tr_TR.inc b/plugins/password/localization/tr_TR.inc new file mode 100644 index 000000000..4f2322a2e --- /dev/null +++ b/plugins/password/localization/tr_TR.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = 'Parolayı Değiştir'; +$labels['curpasswd'] = 'Şu anki Parola:'; +$labels['newpasswd'] = 'Yeni Parola:'; +$labels['confpasswd'] = 'Yeni Parolayı Onaylayın:'; + +$messages = array(); +$messages['nopassword'] = 'Lütfen yeni şifreyi girin.'; +$messages['nocurpassword'] = 'Lütfen şu anki şifrenizi girin.'; +$messages['passwordincorrect'] = 'Parolanızı yanlış girdiniz.'; +$messages['passwordinconsistency'] = 'Girdiğiniz parolalar uyuşmuyor. Lütfen tekrar deneyin..'; +$messages['crypterror'] = 'Yeni şifre kaydedilemedi. Gerekli fonksiyon eksik.'; +$messages['connecterror'] = 'Yeni şifre kaydedilemedi. Bağlantı hatası.'; +$messages['internalerror'] = 'Yeni şifre kaydedilemedi.'; +$messages['passwordshort'] = 'Parola en az $length karakterden oluşmalı.'; +$messages['passwordweak'] = 'Parola en az bir sayı ve bir noktalama işareti içermeli.'; +$messages['passwordforbidden'] = 'Parola uygunsuz karakter(ler) içeriyor.'; + +?> diff --git a/plugins/password/localization/zh_TW.inc b/plugins/password/localization/zh_TW.inc new file mode 100644 index 000000000..7d162274a --- /dev/null +++ b/plugins/password/localization/zh_TW.inc @@ -0,0 +1,21 @@ +<?php + +$labels = array(); +$labels['changepasswd'] = '更改密碼'; +$labels['curpasswd'] = '目前的密碼'; +$labels['newpasswd'] = '新密碼'; +$labels['confpasswd'] = '確認新密碼'; + +$messages = array(); +$messages['nopassword'] = '請輸入新密碼'; +$messages['nocurpassword'] = '請輸入目前的密碼'; +$messages['passwordincorrect'] = '目前的密碼錯誤'; +$messages['passwordinconsistency'] = '密碼不相符,請重新輸入'; +$messages['crypterror'] = '無法更新密碼:無加密機制'; +$messages['connecterror'] = '無法更新密碼:連線失敗'; +$messages['internalerror'] = '無法更新密碼'; +$messages['passwordshort'] = '您的密碼至少需 $length 個字元長'; +$messages['passwordweak'] = '您的新密碼至少需含有一個數字與一個標點符號'; +$messages['passwordforbidden'] = '您的密碼含有禁用字元'; + +?> diff --git a/plugins/password/package.xml b/plugins/password/package.xml new file mode 100644 index 000000000..a4f74c192 --- /dev/null +++ b/plugins/password/package.xml @@ -0,0 +1,267 @@ +<?xml version="1.0" encoding="UTF-8"?> +<package xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" packagerversion="1.9.0" version="2.0" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 + http://pear.php.net/dtd/tasks-1.0.xsd + http://pear.php.net/dtd/package-2.0 + http://pear.php.net/dtd/package-2.0.xsd"> + <name>password</name> + <channel>pear.roundcube.net</channel> + <summary>Password Change for Roundcube</summary> + <description>Plugin that adds a possibility to change user password using many + methods (drivers) via Settings/Password tab. + </description> + <lead> + <name>Aleksander Machniak</name> + <user>alec</user> + <email>alec@alec.pl</email> + <active>yes</active> + </lead> + <date></date> + <time></time> + <version> + <release></release> + <api>1.6</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- When old and new passwords are the same, do nothing, return success (#1487823) +- Fixed Samba password hashing in 'ldap' driver +- Added 'password_change' hook for plugin actions after successful password change + </notes> + <contents> + <dir baseinstalldir="/" name="/"> + <file name="password.php" role="php"> + <tasks:replace from="@name@" to="name" type="package-info"/> + <tasks:replace from="@package_version@" to="version" type="package-info"/> + </file> + <file name="password.js" role="data"> + <tasks:replace from="@name@" to="name" type="package-info"/> + <tasks:replace from="@package_version@" to="version" type="package-info"/> + </file> + <file name="README" role="data"> + <tasks:replace from="@name@" to="name" type="package-info"/> + <tasks:replace from="@package_version@" to="version" type="package-info"/> + </file> + <file name="localization/az_AZ.inc" role="data"></file> + <file name="localization/bg_BG.inc" role="data"></file> + <file name="localization/ca_ES.inc" role="data"></file> + <file name="localization/cs_CZ.inc" role="data"></file> + <file name="localization/da_DK.inc" role="data"></file> + <file name="localization/de_CH.inc" role="data"></file> + <file name="localization/de_DE.inc" role="data"></file> + <file name="localization/en_US.inc" role="data"></file> + <file name="localization/es_ES.inc" role="data"></file> + <file name="localization/et_EE.inc" role="data"></file> + <file name="localization/fi_FI.inc" role="data"></file> + <file name="localization/fr_FR.inc" role="data"></file> + <file name="localization/gl_ES.inc" role="data"></file> + <file name="localization/hu_HU.inc" role="data"></file> + <file name="localization/it_IT.inc" role="data"></file> + <file name="localization/lt_LT.inc" role="data"></file> + <file name="localization/lv_LV.inc" role="data"></file> + <file name="localization/nl_NL.inc" role="data"></file> + <file name="localization/pl_PL.inc" role="data"></file> + <file name="localization/pt_BR.inc" role="data"></file> + <file name="localization/pt_PT.inc" role="data"></file> + <file name="localization/sl_SI.inc" role="data"></file> + <file name="localization/sv_SE.inc" role="data"></file> + <file name="localization/zh_TW.inc" role="data"></file> + + <file name="drivers/chgsaslpasswd.c" role="data"></file> + <file name="drivers/chgvirtualminpasswd.c" role="data"></file> + <file name="drivers/chpasswd.php" role="php"></file> + <file name="drivers/directadmin.php" role="php"></file> + <file name="drivers/ldap.php" role="php"></file> + <file name="drivers/ldap_simple.php" role="php"></file> + <file name="drivers/poppassd.php" role="php"></file> + <file name="drivers/sql.php" role="php"></file> + <file name="drivers/vpopmaild.php" role="php"></file> + <file name="drivers/cpanel.php" role="php"></file> + <file name="drivers/hmail.php" role="php"></file> + <file name="drivers/pam.php" role="php"></file> + <file name="drivers/sasl.php" role="php"></file> + <file name="drivers/virtualmin.php" role="php"></file> + <file name="drivers/ximss.php" role="php"></file> + <file name="drivers/xmail.php" role="php"></file> + <file name="drivers/chpass-wrapper.py" role="data"></file> + + <file name="config.inc.php.disc" role="data"></file> + </dir> + <!-- / --> + </contents> + <dependencies> + <required> + <php> + <min>5.2.1</min> + </php> + <pearinstaller> + <min>1.7.0</min> + </pearinstaller> + </required> + </dependencies> + <phprelease/> + <changelog> + <release> + <date>2010-04-29</date> + <time>12:00:00</time> + <version> + <release>1.4</release> + <api>1.4</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- Use mail_domain value for domain variables when there is no domain in username: + sql and ldap drivers (#1486694) +- Created package.xml + </notes> + </release> + <release> + <date>2010-06-20</date> + <time>12:00:00</time> + <version> + <release>1.5</release> + <api>1.5</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- Removed user_login/username_local/username_domain methods, + use rcube_user::get_username instead (#1486707) + </notes> + </release> + <release> + <date>2010-08-01</date> + <time>09:00:00</time> + <version> + <release>1.6</release> + <api>1.5</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- Added ldap_simple driver + </notes> + </release> + <release> + <date>2010-09-10</date> + <time>09:00:00</time> + <version> + <release>1.7</release> + <api>1.5</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- Added XMail driver +- Improve security of chpasswd driver using popen instead of exec+echo (#1486987) +- Added chpass-wrapper.py script to improve security (#1486987) + </notes> + </release> + <release> + <date>2010-09-29</date> + <time>19:00:00</time> + <version> + <release>1.8</release> + <api>1.6</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- Added possibility to display extended error messages (#1486704) +- Added extended error messages in Poppassd driver (#1486704) + </notes> + </release> + <release> + <version> + <release>1.9</release> + <api>1.6</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- Added password_ldap_lchattr option (#1486927) + </notes> + </release> + <release> + <date>2010-10-07</date> + <time>09:00:00</time> + <version> + <release>2.0</release> + <api>1.6</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- Fixed SQL Injection in SQL driver when using %p or %o variables in query (#1487034) + </notes> + </release> + <release> + <date>2010-11-02</date> + <time>09:00:00</time> + <version> + <release>2.1</release> + <api>1.6</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- hMail driver: Add possibility to connect to remote host + </notes> + </release> + <release> + <date>2011-02-15</date> + <time>12:00</time> + <version> + <release>2.2</release> + <api>1.6</api> + </version> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <license uri="http://www.gnu.org/licenses/gpl-2.0.html">GNU GPLv2</license> + <notes> +- hMail driver: add username_domain detection (#1487100) +- hMail driver: HTML tags in logged messages should be stripped off (#1487099) +- Chpasswd driver: add newline at end of input to chpasswd binary (#1487141) +- Fix usage of configured temp_dir instead of /tmp (#1487447) +- ldap_simple driver: fix parse error +- ldap/ldap_simple drivers: support %dc variable in config +- ldap/ldap_simple drivers: support Samba password change +- Fix extended error messages handling (#1487676) +- Fix double request when clicking on Password tab in Firefox +- Fix deprecated split() usage in xmail and directadmin drivers (#1487769) +- Added option (password_log) for logging password changes +- Virtualmin driver: Add option for setting username format (#1487781) + </notes> + </release> + </changelog> +</package> diff --git a/plugins/password/password.js b/plugins/password/password.js new file mode 100644 index 000000000..26376b36d --- /dev/null +++ b/plugins/password/password.js @@ -0,0 +1,37 @@ +/* + * Password plugin script + * @version @package_version@ + */ + +if (window.rcmail) { + rcmail.addEventListener('init', function(evt) { + // <span id="settingstabdefault" class="tablink"><roundcube:button command="preferences" type="link" label="preferences" title="editpreferences" /></span> + var tab = $('<span>').attr('id', 'settingstabpluginpassword').addClass('tablink'); + var button = $('<a>').attr('href', rcmail.env.comm_path+'&_action=plugin.password') + .html(rcmail.gettext('password')).appendTo(tab); + + // add button and register commands + rcmail.add_element(tab, 'tabs'); + rcmail.register_command('plugin.password-save', function() { + var input_curpasswd = rcube_find_object('_curpasswd'); + var input_newpasswd = rcube_find_object('_newpasswd'); + var input_confpasswd = rcube_find_object('_confpasswd'); + + if (input_curpasswd && input_curpasswd.value=='') { + alert(rcmail.gettext('nocurpassword', 'password')); + input_curpasswd.focus(); + } else if (input_newpasswd && input_newpasswd.value=='') { + alert(rcmail.gettext('nopassword', 'password')); + input_newpasswd.focus(); + } else if (input_confpasswd && input_confpasswd.value=='') { + alert(rcmail.gettext('nopassword', 'password')); + input_confpasswd.focus(); + } else if (input_newpasswd && input_confpasswd && input_newpasswd.value != input_confpasswd.value) { + alert(rcmail.gettext('passwordinconsistency', 'password')); + input_newpasswd.focus(); + } else { + rcmail.gui_objects.passform.submit(); + } + }, true); + }) +} diff --git a/plugins/password/password.php b/plugins/password/password.php new file mode 100644 index 000000000..b1c7863fc --- /dev/null +++ b/plugins/password/password.php @@ -0,0 +1,274 @@ +<?php + +/* + +-------------------------------------------------------------------------+ + | Password Plugin for Roundcube | + | @version @package_version@ | + | | + | Copyright (C) 2009-2010, Roundcube Dev. | + | | + | This program is free software; you can redistribute it and/or modify | + | it under the terms of the GNU General Public License version 2 | + | 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, write to the Free Software Foundation, Inc., | + | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. | + | | + +-------------------------------------------------------------------------+ + | Author: Aleksander Machniak <alec@alec.pl> | + +-------------------------------------------------------------------------+ + + $Id: index.php 2645 2009-06-15 07:01:36Z alec $ + +*/ + +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'; + public $noframe = true; + public $noajax = true; + + function init() + { + $rcmail = rcmail::get_instance(); + // add Tab label + $rcmail->output->add_label('password'); + $this->register_action('plugin.password', array($this, 'password_init')); + $this->register_action('plugin.password-save', array($this, 'password_save')); + $this->include_script('password.js'); + } + + function password_init() + { + $this->add_texts('localization/'); + $this->register_handler('plugin.body', array($this, 'password_form')); + + $rcmail = rcmail::get_instance(); + $rcmail->output->set_pagetitle($this->gettext('changepasswd')); + $rcmail->output->send('plugin'); + } + + function password_save() + { + $rcmail = rcmail::get_instance(); + $this->load_config(); + + $this->add_texts('localization/'); + $this->register_handler('plugin.body', array($this, 'password_form')); + $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 ? get_input_value('_curpasswd', RCUBE_INPUT_POST, true, $charset) : $sespwd; + $newpwd = get_input_value('_newpasswd', RCUBE_INPUT_POST, true); + $conpwd = get_input_value('_confpasswd', RCUBE_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->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')) { + write_log('password', sprintf('Password changed for user %s (ID: %d) from %s', + $rcmail->user->get_username(), $rcmail->user->ID, rcmail_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(); + $this->load_config(); + + // 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, 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, 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, Q($this->gettext('confpasswd')))); + $table->add(null, $input_confpasswd->show()); + + $out = html::div(array('class' => 'box'), + html::div(array('id' => 'prefs-title', 'class' => 'boxtitle'), $this->gettext('changepasswd')) . + html::div(array('class' => 'boxcontent'), $table->show() . + 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 = $this->home.'/drivers/'.$config->get('password_driver', 'sql').'.php'; + + if (!is_readable($driver)) { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: Unable to open driver file $driver" + ), true, false); + return $this->gettext('internalerror'); + } + + include($driver); + + if (!function_exists('password_save')) { + raise_error(array( + 'code' => 600, + 'type' => 'php', + 'file' => __FILE__, 'line' => __LINE__, + 'message' => "Password plugin: Broken driver: $driver" + ), true, false); + return $this->gettext('internalerror'); + } + + $result = password_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'); + case PASSWORD_CONNECT_ERROR; + $reason = $this->gettext('connecterror'); + case PASSWORD_ERROR: + default: + $reason = $this->gettext('internalerror'); + } + + if ($message) { + $reason .= ' ' . $message; + } + + return $reason; + } +} |