X-Git-Url: https://vcs.fsf.org/?p=squirrelmail.git;a=blobdiff_plain;f=plugins%2Fchange_password%2Fbackend%2Fldap.php;h=d325cb3cf84ff6c21d2c273f5a8e64959952a572;hp=b4562c6e434355fbeeb21b39023ad6ffc24736cb;hb=b4df37a525c34a317d5f6ff10baa518f75448703;hpb=02c81de496ba189cf1dca6d9588ea434f93ee3da diff --git a/plugins/change_password/backend/ldap.php b/plugins/change_password/backend/ldap.php index b4562c6e..d325cb3c 100644 --- a/plugins/change_password/backend/ldap.php +++ b/plugins/change_password/backend/ldap.php @@ -1,41 +1,60 @@ *
  • 'ldap.example.com' - connect to server on ldap.example.com address - *
  • 'ldaps://ldap.example.com' - connect to server on ldap.example.com address - * and use SSL encrypted connection to default ldaps port. + *
  • 'ldaps://ldap.example.com' - connect to server on ldap.example.com address + * and use SSL encrypted connection to default LDAPs port. * * defaults to imap server address. * @link http://www.php.net/ldap-connect * @global string $cpw_ldap_server */ global $cpw_ldap_server; -$cpw_ldap_server='localhost'; +$cpw_ldap_server=$imapServerAddress; /** - * Port of ldap server. - * Used only when $cpw_ldap_server specifies ip address or dns name. + * Port of LDAP server. + * Used only when $cpw_ldap_server specifies IP address or DNS name. * @global integer $cpw_ldap_port */ global $cpw_ldap_port; $cpw_ldap_port=389; /** - * ldap basedn that is used for binding to ldap server. + * LDAP basedn that is used for binding to LDAP server. * this option must be set to correct value. - * @global $cpw_ldap_basedn; + * @global string $cpw_ldap_basedn; */ global $cpw_ldap_basedn; $cpw_ldap_basedn=''; @@ -49,8 +68,8 @@ global $cpw_ldap_connect_opts; $cpw_ldap_connect_opts=array(); /** - * Controls use of starttls on ldap connection. - * Requires php 4.2+, php ldap extension with ssl support and + * Controls use of starttls on LDAP connection. + * Requires PHP 4.2+, PHP LDAP extension with SSL support and * PROTOCOL_VERSION => 3 setting in $cpw_ldap_connect_opts * @global boolean $cpw_ldap_use_tls */ @@ -58,9 +77,9 @@ global $cpw_ldap_use_tls; $cpw_ldap_use_tls=false; /** - * BindDN that should be able to search ldap directory and find DN used by user. - * Uses anonymous bind if set to empty string. You should not use DN with write - * access to ldap directory here. Write access is not required. + * BindDN that should be able to search LDAP directory and find DN used by user. + * Uses anonymous bind if set to empty string. You should not use DN with write + * access to LDAP directory here. Write access is not required. * @global string $cpw_ldap_binddn */ global $cpw_ldap_binddn; @@ -68,15 +87,15 @@ $cpw_ldap_binddn=''; /** * password used for $cpw_ldap_binddn - * @global string $cpw_ldap_bindpw + * @global string $cpw_ldap_bindpw */ global $cpw_ldap_bindpw; $cpw_ldap_bindpw=''; /** * BindDN that should be able to change password. - * WARNING: usually user has enough privileges to change own password. - * If you leave default value, plugin will try to connect with dn that + * WARNING: sometimes user has enough privileges to change own password. + * If you leave default value, plugin will try to connect with DN that * is detected in $cpw_ldap_username_attr=$username search and current * user password will be used for authentication. * @global string $cpw_ldap_admindn @@ -86,13 +105,13 @@ $cpw_ldap_admindn=''; /** * password used for $cpw_ldap_admindn - * @global string $cpw_ldap_adminpw + * @global string $cpw_ldap_adminpw */ global $cpw_ldap_adminpw; $cpw_ldap_adminpw=''; /** - * ldap attribute that stores username. + * LDAP attribute that stores username. * username entry should be unique for $cpw_ldap_basedn * @global string $cpw_ldap_userid_attr */ @@ -122,6 +141,9 @@ if (isset($cpw_ldap['adminpw'])) $cpw_ldap_adminpw=$cpw_ldap['adminpw']; if (isset($cpw_ldap['userid_attr'])) $cpw_ldap_userid_attr=$cpw_ldap['userid_attr']; if (isset($cpw_ldap['default_crypto'])) $cpw_ldap_default_crypto=$cpw_ldap['default_crypto']; +/** make sure that setting does not contain mapping */ +$cpw_ldap_server=sqimap_get_user_server($cpw_ldap_server,$username); + /** * Adding plugin hooks */ @@ -132,50 +154,41 @@ $squirrelmail_plugin_hooks['change_password_init']['ldap'] = 'cpw_ldap_init'; /** - * Backend specific functions + * Makes sure that required functions and configuration options are set. */ function cpw_ldap_init() { - global $color; - global $cpw_ldap_basedn; - - /** - * If SM_PATH isn't defined, define it. Required to include files. - * @ignore - */ - if (!defined('SM_PATH')) define('SM_PATH','../../../'); - - // load error_box() function - include_once(SM_PATH . 'functions/display_messages.php'); + global $oTemplate, $cpw_ldap_basedn; // set initial value for error tracker $cpw_ldap_initerr=false; // check for ldap support in php if (! function_exists('ldap_connect')) { - error_box(_("Current configuration requires ldap support in php."),$color); + error_box(_("Current configuration requires LDAP support in PHP.")); $cpw_ldap_initerr=true; } // chech required configuration settings. if ($cpw_ldap_basedn=='') { - error_box(_("Plugin is not configured correctly."),$color); + error_box(_("Plugin is not configured correctly.")); $cpw_ldap_initerr=true; } - // if error var is positive, close html and stop execution + // if error var is positive, close html and stop execution if ($cpw_ldap_initerr) { - echo ''; + $oTemplate->display('footer.tpl'); exit; } } /** + * Changes password. Main function attached to hook * @param array $data The username/curpw/newpw data. * @return array Array of error messages. */ function cpw_ldap_dochange($data) { - global $cpw_ldap_server, $cpw_ldap_port, $cpw_ldap_basedn, + global $cpw_ldap_server, $cpw_ldap_port, $cpw_ldap_basedn, $cpw_ldap_connect_opts,$cpw_ldap_use_tls, $cpw_ldap_binddn, $cpw_ldap_bindpw, $cpw_ldap_admindn, $cpw_ldap_adminpw; @@ -191,26 +204,39 @@ function cpw_ldap_dochange($data) { $msgs = array(); /** - * connect to ldap server + * connect to LDAP server * hide ldap_connect() function call errors, because they are processed in script. - * any script execution error is treated as critical, error messages are dumped - * to $msgs and ldap connection is closed with ldap_unbind(). all ldap_unbind() + * any script execution error is treated as critical, error messages are dumped + * to $msgs and LDAP connection is closed with ldap_unbind(). all ldap_unbind() * errors are suppressed. Any other error suppression should be explained. */ $cpw_ldap_con=@ldap_connect($cpw_ldap_server); if ($cpw_ldap_con) { $cpw_ldap_con_err=false; + // set connection options if (is_array($cpw_ldap_connect_opts) && $cpw_ldap_connect_opts!=array()) { - foreach ($cpw_ldap_connect_opts as $opt => $value) { - if (! ldap_set_option($cpw_ldap_con,constant('LDAP_OPT_' . $opt),$value)) { - // set error message - array_push($msgs,sprintf(_("Setting of ldap connection option %s to value %s failed."),$opt,$value)); - // FIXME: check if ldap_set_option modifies ldap_error. - array_push($msgs,sprintf(_("Error: %s"),ldap_error($cpw_ldap_con))); - $cpw_ldap_con_err=true; + // ldap_set_option() is available only with openldap 2.x and netscape directory sdk. + if (function_exists('ldap_set_option')) { + foreach ($cpw_ldap_connect_opts as $opt => $value) { + // Make sure that constant is defined defore using it. + if (defined('LDAP_OPT_' . $opt)) { + // ldap_set_option() should not produce E_NOTICE or E_ALL errors and does not modify ldap_error(). + // leave it without @ in order to see any weird errors + if (! ldap_set_option($cpw_ldap_con,constant('LDAP_OPT_' . $opt),$value)) { + // set error message + array_push($msgs,sprintf(_("Setting of LDAP connection option %s to value %s failed."),$opt,$value)); + $cpw_ldap_con_err=true; + } + } else { + array_push($msgs,sprintf(_("Incorrect LDAP connection option: %s"),$opt)); + $cpw_ldap_con_err=true; + } } + } else { + array_push($msgs,_("Current PHP LDAP extension does not allow use of ldap_set_option() function.")); + $cpw_ldap_con_err=true; } } @@ -220,15 +246,17 @@ function cpw_ldap_dochange($data) { return $msgs; } - // enable tls - // FIXME: untested. use of undocumented ldap function + // enable ldap starttls if ($cpw_ldap_use_tls && check_php_version(4,2,0) && isset($cpw_ldap_connect_opts['PROTOCOL_VERSION']) && - $cpw_ldap_connect_opts['PROTOCOL_VERSION']>=3) { - if (! ldap_use_tls($cpw_ldap_con)) { - array_push($msgs,_("Unable to use TLS.")); - array_push($msgs,sprintf(_("Error: %s"),ldap_error($cpw_ldap_con))); + $cpw_ldap_connect_opts['PROTOCOL_VERSION']>=3 && + function_exists('ldap_start_tls')) { + // suppress ldap_start_tls errors and process error messages + if (! @ldap_start_tls($cpw_ldap_con)) { + array_push($msgs, + _("Unable to use TLS."), + sprintf(_("Error: %s"),ldap_error($cpw_ldap_con))); $cpw_ldap_con_err=true; } } elseif ($cpw_ldap_use_tls) { @@ -243,7 +271,7 @@ function cpw_ldap_dochange($data) { } /** - * bind to ldap (use anonymous bind or unprivileged dn) in order to get user's dn + * Bind to LDAP (use anonymous bind or unprivileged DN) in order to get user's DN * hide ldap_bind() function call errors, because errors are processed in script */ if ($cpw_ldap_binddn!='') { @@ -256,8 +284,9 @@ function cpw_ldap_dochange($data) { // check ldap_bind errors if (! $cpw_ldap_binding) { - array_push($msgs,_("Unable to bind to ldap server")); - array_push($msgs,sprintf(_("Server replied: %s"),ldap_error($cpw_ldap_con))); + array_push($msgs, + _("Unable to bind to LDAP server."), + sprintf(_("Server replied: %s"),ldap_error($cpw_ldap_con))); @ldap_unbind($cpw_ldap_con); return $msgs; } @@ -267,16 +296,16 @@ function cpw_ldap_dochange($data) { // check for search errors and stop execution if something is wrong if (! $cpw_ldap_search_err) { - ldap_unbind($cpw_ldap_con); + @ldap_unbind($cpw_ldap_con); return $msgs; } /** * unset $cpw_ldap_res2 variable, if such var exists. - * $cpw_ldap_res2 object can be set in two places and second place checks, - * if object was created in first place. if variable name matches (somebody - * uses $cpw_ldap_res2 in code or globals), incorrect validation might - * cause script errors. + * $cpw_ldap_res2 object can be set in two places and second place checks, + * if object was created in first place. if variable name matches (somebody + * uses $cpw_ldap_res2 in code or globals), incorrect validation might + * cause script errors. */ if (isset($cpw_ldap_res2)) unset($cpw_ldap_res2); @@ -292,17 +321,25 @@ function cpw_ldap_dochange($data) { // check for connection errors and stop execution if something is wrong if (! $cpw_ldap_search_err) { @ldap_unbind($cpw_ldap_con); + // errors are added to msgs by cpw_ldap_uid_search() return $msgs; } // we should check user password here. - $cpw_ldap_cur_pass_array=ldap_get_values($cpw_ldap_con, + // suppress errors and check value returned by function call + $cpw_ldap_cur_pass_array=@ldap_get_values($cpw_ldap_con, ldap_first_entry($cpw_ldap_con,$cpw_ldap_res2),'userpassword'); - // FIXME: check if ldap_get_values() found userpassword field. Currently it might cause php errors + + // check if ldap_get_values() have found userpassword field + if (! $cpw_ldap_cur_pass_array) { + array_push($msgs,_("Unable to find user's password attribute.")); + return $msgs; + } // compare passwords if (! cpw_ldap_compare_pass($cpw_ldap_cur_pass_array[0],$curpw,$msgs)) { @ldap_unbind($cpw_ldap_con); + // errors are added to $msgs by cpw_ldap_compare_pass() return $msgs; } } @@ -311,8 +348,9 @@ function cpw_ldap_dochange($data) { } if (! $cpw_ldap_binding) { - array_push($msgs,_("Unable to rebind to ldap server")); - array_push($msgs,sprintf(_("Server replied: %s"),ldap_error($cpw_ldap_con))); + array_push($msgs, + _("Unable to rebind to LDAP server."), + sprintf(_("Server replied: %s"),ldap_error($cpw_ldap_con))); @ldap_unbind($cpw_ldap_con); return $msgs; } @@ -327,9 +365,15 @@ function cpw_ldap_dochange($data) { return $msgs; } - // getpassword - $cpw_ldap_cur_pass_array=ldap_get_values($cpw_ldap_con,ldap_first_entry($cpw_ldap_con,$cpw_ldap_res2),'userpassword'); - // FIXME: check if ldap_get_values() found userpassword field + // getpassword. suppress errors and check value returned by function call + $cpw_ldap_cur_pass_array=@ldap_get_values($cpw_ldap_con,ldap_first_entry($cpw_ldap_con,$cpw_ldap_res2),'userpassword'); + + // check if ldap_get_values() have found userpassword field. + // Error differs from previous one, because user managed to authenticate. + if (! $cpw_ldap_cur_pass_array) { + array_push($msgs,_("LDAP server uses different attribute to store user's password.")); + return $msgs; + } // encrypt new password (old password is needed for plaintext encryption detection) $cpw_ldap_new_pass=cpw_ldap_encrypt_pass($newpw,$cpw_ldap_cur_pass_array[0],$msgs,$curpw); @@ -339,8 +383,8 @@ function cpw_ldap_dochange($data) { return $msgs; } - // set new password - $ldap_pass_change=ldap_modify($cpw_ldap_con,$cpw_ldap_userdn,array('userpassword'=>$cpw_ldap_new_pass)); + // set new password. suppress ldap_modify errors. script checks and displays ldap_modify errors. + $ldap_pass_change=@ldap_modify($cpw_ldap_con,$cpw_ldap_userdn,array('userpassword'=>$cpw_ldap_new_pass)); // check if ldap_modify was successful if(! $ldap_pass_change) { @@ -358,7 +402,7 @@ function cpw_ldap_dochange($data) { /** backend support functions **/ /** - * Sanitizes ldap query strings. + * Sanitizes LDAP query strings. * original code - ldapquery plugin. * See rfc2254 * @link http://www.faqs.org/rfcs/rfc2254.html @@ -389,11 +433,11 @@ function cpw_ldap_get_crypto($pass,$curpass='') { if ($ret=='crypt') { // {CRYPT} can be standard des crypt, extended des crypt, md5 crypt or blowfish - // depends on first salt symbols (ext_des = '_', md5 = '$1$', blowfish = '$2$') + // depends on first salt symbols (ext_des = '_', md5 = '$1$', blowfish = '$2') // and length of salt (des = 2 chars, ext_des = 9, md5 = 12, blowfish = 16). if (preg_match("/^\{crypt\}\\\$1\\\$+/i",$pass)) { $ret='md5crypt'; - } elseif (preg_match("/^\{crypt\}\\\$2\\\$+/i",$pass)) { + } elseif (preg_match("/^\{crypt\}\\\$2+/i",$pass)) { $ret='blowfish'; } elseif (preg_match("/^\{crypt\}_+/i",$pass)) { $ret='extcrypt'; @@ -407,7 +451,7 @@ function cpw_ldap_get_crypto($pass,$curpass='') { } /** - * search ldap for user id. + * Search LDAP for user id. * @param object $ldap_con ldap connection * @param string $ldap_basedn ldap basedn * @param array $msgs error messages @@ -424,24 +468,28 @@ function cpw_ldap_uid_search($ldap_con,$ldap_basedn,&$msgs,&$results,&$userdn,$o $results=ldap_search($ldap_con,$ldap_basedn,cpw_ldap_specialchars($cpw_ldap_userid_attr . '=' . $username)); if (! $results) { - array_push($msgs,_("Unable to find user's dn.") . _("Search error.")); - array_push($msgs,sprintf(_("Error: %s"),ldap_error($ldap_con))); + array_push($msgs, + _("Unable to find user's DN."), + _("Search error."), + sprintf(_("Error: %s"),ldap_error($ldap_con))); $ret=false; } elseif ($onlyone && ldap_count_entries($ldap_con,$results)>1) { array_push($msgs,_("Multiple userid matches found.")); $ret=false; } elseif (! $userdn = ldap_get_dn($ldap_con,ldap_first_entry($ldap_con,$results))) { // ldap_get_dn() returned error - array_push($msgs,_("Unable to find user's dn.") . _("ldap_get_dn error.")); + array_push($msgs, + _("Unable to find user's DN."), + _("ldap_get_dn error.")); $ret=false; } return $ret; } /** - * encrypts ldap password + * Encrypts LDAP password * - * if $cpw_ldap_default_crypto is set to empty string or $same_crypto is set, + * if $cpw_ldap_default_crypto is set to empty string or $same_crypto is set, * uses same crypto as in old password. * See phpldapadmin password_hash() function * @link http://phpldapadmin.sf.net @@ -486,12 +534,22 @@ function cpw_ldap_password_hash($pass,$crypto,&$msgs,$forced_salt='') { // encrypt/hash password switch ($crypto) { + case 'md4': + // minimal requirement = php with mhash extension + if ( function_exists( 'mhash' ) && defined('MHASH_MD4')) { + $ret = '{MD4}' . base64_encode( mhash( MHASH_MD4, $pass) ); + } else { + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'md4'), + _("PHP mhash extension is missing or does not support selected crypto.")); + } + break; case 'md5': $ret='{MD5}' . base64_encode(pack('H*',md5($pass))); break; case 'smd5': - // minimal requirement mhash extension and php 4.0.4. - if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) { + // minimal requirement = mhash extension with md5 support and php 4.0.4. + if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) && defined('MHASH_MD5')) { sq_mt_seed( (double) microtime() * 1000000 ); if ($forced_salt!='') { $salt=$forced_salt; @@ -500,20 +558,38 @@ function cpw_ldap_password_hash($pass,$crypto,&$msgs,$forced_salt='') { } $ret = "{SMD5}".base64_encode( mhash( MHASH_MD5, $pass.$salt ).$salt ); } else { - array_push($msgs,sprintf(_("Unsupported crypto: %s"),'smd5') . _("php mhash extension is missing.")); + // use two array_push calls in order to display messages in different lines. + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'smd5'), + _("PHP mhash extension is missing or does not support selected crypto.")); + } + break; + case 'rmd160': + // minimal requirement = php with mhash extension + if ( function_exists( 'mhash' ) && defined('MHASH_RIPEMD160')) { + $ret = '{RMD160}' . base64_encode( mhash( MHASH_RIPEMD160, $pass) ); + } else { + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'ripe-md160'), + _("PHP mhash extension is missing or does not support selected crypto.")); } break; case 'sha': - // minimal requirement = mhash extension - if( function_exists( 'mhash' ) ) { + // minimal requirement = php 4.3.0+ or php with mhash extension + if ( function_exists('sha1') && defined('MHASH_SHA1')) { + // use php 4.3.0+ sha1 function, if it is available. + $ret = '{SHA}' . base64_encode(pack('H*',sha1($pass))); + } elseif( function_exists( 'mhash' ) ) { $ret = '{SHA}' . base64_encode( mhash( MHASH_SHA1, $pass) ); } else { - array_push($msgs,sprintf(_("Unsupported crypto: %s"),'sha') . _("php mhash extension is missing.")); + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'sha'), + _("PHP mhash extension is missing or does not support selected crypto.")); } break; case 'ssha': // minimal requirement = mhash extension and php 4.0.4 - if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) { + if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) && defined('MHASH_SHA1')) { sq_mt_seed( (double) microtime() * 1000000 ); if ($forced_salt!='') { $salt=$forced_salt; @@ -522,16 +598,18 @@ function cpw_ldap_password_hash($pass,$crypto,&$msgs,$forced_salt='') { } $ret = "{SSHA}".base64_encode( mhash( MHASH_SHA1, $pass.$salt ).$salt ); } else { - array_push($msgs,sprintf(_("Unsupported crypto: %s"),'ssha') - . _("php mhash extension is missing.")); + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'ssha'), + _("PHP mhash extension is missing or does not support selected crypto.")); } break; case 'crypt': if (defined('CRYPT_STD_DES') && CRYPT_STD_DES==1) { $ret = '{CRYPT}' . crypt($pass,GenerateRandomString(2,$extra_salt_chars,7)); } else { - array_push($msgs,sprintf(_("Unsupported crypto: %s"),'crypt') - . _("System crypt library doesn't support standard des crypt.")); + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'crypt'), + _("System crypt library doesn't support standard DES crypt.")); } break; case 'md5crypt': @@ -539,28 +617,29 @@ function cpw_ldap_password_hash($pass,$crypto,&$msgs,$forced_salt='') { if (defined('CRYPT_MD5') && CRYPT_MD5==1) { $ret = '{CRYPT}' . crypt($pass,'$1$' . GenerateRandomString(9,$extra_salt_chars,7)); } else { - array_push($msgs,sprintf(_("Unsupported crypto: %s"),'md5crypt') - . _("System crypt library doesn't have md5 support.")); + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'md5crypt'), + _("System crypt library doesn't have MD5 support.")); } break; case 'extcrypt': // check if crypt() supports extended des if (defined('CRYPT_EXT_DES') && CRYPT_EXT_DES==1) { - // FIXME: guinea pigs with extended des support needed. $ret = '{CRYPT}' . crypt($pass,'_' . GenerateRandomString(8,$extra_salt_chars,7)); } else { - array_push($msgs,sprintf(_("Unsupported crypto: %s"),'ext_des') - . _("System crypt library doesn't support extended des crypt.")); + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'ext_des'), + _("System crypt library doesn't support extended DES crypt.")); } break; case 'blowfish': // check if crypt() supports blowfish if (defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH==1) { - // FIXME: guinea pigs with blowfish support needed. - $ret = '{CRYPT}' . crypt($pass,'$2$' . GenerateRandomString(13,$extra_salt_chars,7)); + $ret = '{CRYPT}' . crypt($pass,'$2a$12$' . GenerateRandomString(13,$extra_salt_chars,7)); } else { - array_push($msgs,sprintf(_("Unsupported crypto: %s"),'blowfish') - . _("System crypt library doesn't have blowfish support.")); + array_push($msgs, + sprintf(_("Unsupported crypto: %s"),'Blowfish'), + _("System crypt library doesn't have Blowfish support.")); } break; case 'plaintext': @@ -579,9 +658,9 @@ function cpw_ldap_password_hash($pass,$crypto,&$msgs,$forced_salt='') { * Code reuse. See phpldapadmin password_compare() function. * Some parts of code was rewritten to backend specifics. * @link http://phpldapadmin.sf.net - * @param string $pass_hash - * @param string $pass_clear - * @param array $msgs + * @param string $pass_hash hashed password string with password type indicators + * @param string $pass_clear plain text password + * @param array $msgs error messages * @return boolean true, if passwords match */ function cpw_ldap_compare_pass($pass_hash,$pass_clear,&$msgs) { @@ -598,29 +677,31 @@ function cpw_ldap_compare_pass($pass_hash,$pass_clear,&$msgs) { case 'ssha': // Salted SHA // check for mhash support - if ( function_exists('mhash') ) { + if ( function_exists('mhash') && defined('MHASH_SHA1')) { $hash = base64_decode($pass_hash); $salt = substr($hash, -4); $new_hash = base64_encode( mhash( MHASH_SHA1, $pass_clear.$salt).$salt ); if( strcmp( $pass_hash, $new_hash ) == 0 ) $ret=true; } else { - array_push($msgs,_("Unable to validate user's password.")); - array_push($msgs, _("php mhash extension is missing.")); + array_push($msgs, + _("Unable to validate user's password."), + _("PHP mhash extension is missing or does not support selected crypto.")); } break; case 'smd5': // Salted MD5 // check for mhash support - if ( function_exists('mhash') ) { + if ( function_exists('mhash') && defined('MHASH_MD5')) { $hash = base64_decode($pass_hash); $salt = substr($hash, -4); $new_hash = base64_encode( mhash( MHASH_MD5, $pass_clear.$salt).$salt ); if( strcmp( $pass_hash, $new_hash ) == 0) $ret=true; } else { - array_push($msgs,_("Unable to validate user's password.")); - array_push($msgs, _("php mhash extension is missing.")); + array_push($msgs, + _("Unable to validate user's password."), + _("PHP mhash extension is missing or does not support selected crypto.")); } break; case 'sha': @@ -628,23 +709,33 @@ function cpw_ldap_compare_pass($pass_hash,$pass_clear,&$msgs) { if( strcasecmp( cpw_ldap_password_hash($pass_clear,'sha',$msgs), "{SHA}".$pass_hash ) == 0) $ret=true; break; + case 'rmd160': + // RIPE-MD160 crypted passwords + if( strcasecmp( cpw_ldap_password_hash($pass_clear,'rmd160',$msgs), "{RMD160}".$pass_hash ) == 0 ) + $ret=true; + break; case 'md5': // MD5 crypted passwords - if( strcasecmp( cpw_ldap_password_hash( $pass_clear,'md5',$msgs), "{MD5}".$pass_hash ) == 0 ) + if( strcasecmp( cpw_ldap_password_hash($pass_clear,'md5',$msgs), "{MD5}".$pass_hash ) == 0 ) + $ret=true; + break; + case 'md4': + // MD4 crypted passwords + if( strcasecmp( cpw_ldap_password_hash($pass_clear,'md4',$msgs), "{MD4}".$pass_hash ) == 0 ) $ret=true; break; case 'crypt': // Crypt passwords - if( strstr( $pass_hash, '$2$' ) ) { // Check if it's blowfish crypt + if( preg_match( "/^\\\$2+/",$pass_hash ) ) { // Check if it's blowfish crypt // check CRYPT_BLOWFISH here. // ldap server might support it, but php can be on other OS if (defined('CRYPT_BLOWFISH') && CRYPT_BLOWFISH==1) { - list(,$type,$salt,$hash) = explode('$',$pass_hash); - if( crypt( $pass_clear, '$2$' .$salt ) == $pass_hash ) + if( crypt( $pass_clear, $pass_hash ) == $pass_hash ) $ret=true; } else { - array_push($msgs,_("Unable to validate user's password.")); - array_push($msgs,_("Blowfish is not supported by webserver's system crypt library.")); + array_push($msgs, + _("Unable to validate user's password."), + _("Blowfish is not supported by webserver's system crypt library.")); } } elseif( strstr( $pass_hash, '$1$' ) ) { // Check if it's md5 crypt // check CRYPT_MD5 here. @@ -654,8 +745,9 @@ function cpw_ldap_compare_pass($pass_hash,$pass_clear,&$msgs) { if( crypt( $pass_clear, '$1$' .$salt ) == $pass_hash ) $ret=true; } else { - array_push($msgs,_("Unable to validate user's password.")); - array_push($msgs,_("MD5 is not supported by webserver's system crypt library.")); + array_push($msgs, + _("Unable to validate user's password."), + _("MD5 is not supported by webserver's system crypt library.")); } } elseif( strstr( $pass_hash, '_' ) ) { // Check if it's extended des crypt // check CRYPT_EXT_DES here. @@ -664,8 +756,9 @@ function cpw_ldap_compare_pass($pass_hash,$pass_clear,&$msgs) { if( crypt( $pass_clear, $pass_hash ) == $pass_hash ) $ret=true; } else { - array_push($msgs,_("Unable to validate user's password.")); - array_push($msgs,_("Extended DES crypt is not supported by webserver's system crypt library.")); + array_push($msgs, + _("Unable to validate user's password."), + _("Extended DES crypt is not supported by webserver's system crypt library.")); } } else { // it is possible that this test is useless and any crypt library supports it, but ... @@ -674,20 +767,20 @@ function cpw_ldap_compare_pass($pass_hash,$pass_clear,&$msgs) { if( crypt($pass_clear, $pass_hash ) == $pass_hash ) $ret=true; } else { - array_push($msgs,_("Unable to validate user's password.")); - array_push($msgs,_("Standard DES crypt is not supported by webserver's system crypt library.")); + array_push($msgs, + _("Unable to validate user's password."), + _("Standard DES crypt is not supported by webserver's system crypt library.")); } } break; - // No crypt is given assume plaintext passwords are used + // No crypt is given, assume plaintext passwords are used default: if( $pass_clear == $pass_hash ) $ret=true; break; } - if (! $ret) { + if (! $ret && empty($msgs)) { array_push($msgs,CPW_CURRENT_NOMATCH); } return $ret; } -?> \ No newline at end of file