From c8a1e6eb63bb629118b861d2646736fb9f49f710 Mon Sep 17 00:00:00 2001 From: alecpl Date: Fri, 26 Jun 2009 08:31:14 +0000 Subject: - Password plugin: added LDAP driver --- plugins/password/README | 9 +- plugins/password/config.inc.php | 62 +++++++++++++ plugins/password/drivers/ldap.php | 178 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 248 insertions(+), 1 deletion(-) create mode 100644 plugins/password/drivers/ldap.php (limited to 'plugins') diff --git a/plugins/password/README b/plugins/password/README index da21396cb..920d3a36f 100644 --- a/plugins/password/README +++ b/plugins/password/README @@ -29,6 +29,7 @@ 2.1. Database (sql) 2.2. Cyrus/SASL (sasl) 2.3. Poppassd/Courierpassd (poppassd) + 2.4. LDAP (ldap) 3. Driver API @@ -151,12 +152,18 @@ 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 file for more info. + 2.4. LDAP (ldap) + ---------------- + + See config.inc.php file. Requires PEAR::Net_LDAP2 package. + + 3. Driver API ------------- diff --git a/plugins/password/config.inc.php b/plugins/password/config.inc.php index 6107f206f..e70ea7aae 100644 --- a/plugins/password/config.inc.php +++ b/plugins/password/config.inc.php @@ -37,4 +37,66 @@ $rcmail_config['password_pop_host'] = 'localhost'; // TCP port used for poppassd connections $rcmail_config['password_pop_port'] = 106; + +// LDAP 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 replace by the current roundcube user's login +// Exemple: 'uid=%login,ou=people,dc=exemple,dc=com' +$rcmail_config['password_ldap_userDN_mask'] = 'uid=%login,ou=people,dc=exemple,dc=com'; + +// 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'; + ?> diff --git a/plugins/password/drivers/ldap.php b/plugins/password/drivers/ldap.php new file mode 100644 index 000000000..7e92ea525 --- /dev/null +++ b/plugins/password/drivers/ldap.php @@ -0,0 +1,178 @@ + + * + * 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 + $userDN = str_replace('%login', $_SESSION['username'], $rcmail->config->get('password_ldap_userDN_mask')); + if (empty($userDN)) {return PASSWORD_CONNECT_ERROR;} + + // Connection Method + switch($rcmail->config->get('password_ldap_method')) { + case 'user': $binddn = $userDN; $bindpw = $curpass; break; + case 'admin': $binddn = $rcmail->config->get('password_ldap_adminDN'); $bindpw = $rcmail->config->get('password_ldap_adminPW'); break; + default: $binddn = $userDN; $bindpw = $curpass; break; // default is user mode + } + + // 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;} + + // Crypting new password + $newCryptedPassword = hashPassword($passwd, $rcmail->config->get('password_ldap_encodage')); + if (!$newCryptedPassword) {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($rcmail->config->get('password_ldap_pwattr') => $newCryptedPassword))) {return PASSWORD_CONNECT_ERROR;} + if (Net_LDAP2::isError($userEntry->update())) {return PASSWORD_CONNECT_ERROR;} + + // All done, no error + return PASSWORD_SUCCESS; +} + + +/** + * 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 ) {return FALSE;} //Your system crypt library does not support extended DES encryption. + $cryptedPassword = '{CRYPT}' . crypt( $passwordClear, '_' . randomSalt(8) ); + break; + + case 'md5crypt': + if( ! defined( 'CRYPT_MD5' ) || CRYPT_MD5 == 0 ) {return FALSE;} //Your system crypt library does not support md5crypt encryption. + $cryptedPassword = '{CRYPT}' . crypt( $passwordClear , '$1$' . randomSalt(9) ); + break; + + case 'blowfish': + if( ! defined( 'CRYPT_BLOWFISH' ) || CRYPT_BLOWFISH == 0 ) {return FALSE;} //Your system crypt library does not support blowfish encryption. + $cryptedPassword = '{CRYPT}' . crypt( $passwordClear , '$2a$12$' . randomSalt(13) ); // hardcoded to second blowfish version and set number of rounds + 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 '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 --- + * --- ammended 20030625 by S C Rigler --- + * + * @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; +} + +?> -- cgit v1.2.3