1<?php 2/** 3 * Change LDAP Password plugin functions 4 * @copyright (c) 2000-2003 Simon Annetts <simon@ateb.co.uk> 5 * @copyright (c) 2006-2007 The SquirrelMail Project Team 6 * @copyright (c) 2007 The NaSMail Project 7 * @license http://opensource.org/licenses/gpl-license.php GNU Public License 8 * @version $Id: functions.php,v 1.12 2007/07/21 06:56:42 tokul Exp $ 9 * @package plugins 10 * @subpackage change_ldappass 11 */ 12 13/** load configuration */ 14include_once(SM_PATH . 'plugins/change_ldappass/load_config.php'); 15 16/** 17 * Checks user input 18 * @return array 19 */ 20function change_ldappass_check() { 21 global $lcp_crack_dict; 22 23 $cp_oldpass = ''; 24 $cp_newpass = ''; 25 $cp_verify = ''; 26 sqgetGlobalVar('cp_oldpass',$cp_oldpass,SQ_POST); 27 sqgetGlobalVar('cp_newpass',$cp_newpass,SQ_POST); 28 sqgetGlobalVar('cp_verify',$cp_verify,SQ_POST); 29 30 $Messages = array(); 31 if (! extension_loaded('ldap')) { 32 array_push($Messages,_("PHP LDAP extension is not available.")); 33 } 34 if ($cp_oldpass == '') { 35 array_push($Messages, _("You must type in your old password.")); 36 } 37 if ($cp_newpass == '') { 38 array_push($Messages, _("You must type in a new password.")); 39 } 40 41 if ($cp_verify == '') { 42 array_push($Messages,_("You must also type in your new password in the verify box.")); 43 } 44 45 if ($cp_newpass != '' && $cp_verify != $cp_newpass) { 46 array_push($Messages, _("Your new password doesn't match the verify password.")); 47 } 48 49 if (!preg_match("/^[A-Za-z0-9_%=:@#~,\\^\\*\\(\\)\\-\\+\\[\\]\\{\\}\\.\\?]+$/",$cp_newpass)) { 50 // i18n: comma separated list of acceptable characters is listed in next line 51 array_push($Messages, 52 _("Passwords can only contain the following characters:"), 53 "A-Z, a-z, 0-9, %^*()-_+=[]{}:@#~,.?"); 54 } 55 56 // PHP crack support from NaSMail change_password plugin 57 if (! empty($lcp_crack_dict)) { 58 if (! function_exists('crack_opendict')) { 59 $Messages[] = _("PHP Crack extension is not available."); 60 } else { 61 // if crack_opendict command fails, it outputs E_WARNING, 62 // Suppress it and handle error internally. assume that it is dictionary open failure 63 if ($dict = @crack_opendict($lcp_crack_dict)) { 64 if (! crack_check($dict,$cp_newpass)) { 65 $Messages[] = lcp_translate_crack_msg(crack_getlastmessage()); 66 $Messages[] = _("Please choose stronger password."); 67 } 68 crack_closedict($dict); 69 } else { 70 $Messages[] = sprintf(_("Could not open crack dictionary: %s"),$lcp_crack_dict); 71 } 72 } 73 } 74 75 if (count($Messages)) { 76 return $Messages; 77 } 78 return change_ldappass_go($cp_oldpass, $cp_newpass); 79} 80 81/** 82 * Changes password 83 * @param string $cp_oldpass 84 * @param string $cp_newpass 85 */ 86function change_ldappass_go($cp_oldpass, $cp_newpass) { 87 global $username, $ldapsmb_object, $force_smb_sync, $ldap_server, 88 $ldap_protocol_version, $ldap_base_dn, $ldap_password_field, 89 $ldap_user_field, $query_dn, $query_pw, $ldap_filter, 90 $no_bind_as_user, $ldap_bind_as_manager, $ldap_manager_dn, 91 $ldap_manager_pw, $change_ldapsmb, $mkntpwd, 92 $ldapsmb_ntpassword, $ldapsmb_lmpassword, $change_smb, 93 $smb_host, $smb_passwd, $debug; 94 95 $Messages = array(); 96 if ($debug) { 97 array_push($Messages, 'Connecting to LDAP Server'); 98 } 99 100 $ds=ldap_connect($ldap_server); 101 if (! $ds) { 102 array_push($Messages, _("Can't connect to Directory Server, please try later!")); 103 return $Messages; 104 } 105 106 if (function_exists( 'ldap_set_option')) { 107 if (! @ldap_set_option($ds,LDAP_OPT_PROTOCOL_VERSION,$ldap_protocol_version)) { 108 array_push($Messages, _("Unable to set LDAP bind protocol version.")); 109 if ($debug) { 110 array_push($Messages, htmlspecialchars("LDAP bind protocol version: $ldap_protocol_version")); 111 } 112 return $Messages; 113 } else { 114 if ($debug) { 115 array_push($Messages, htmlspecialchars("LDAP protocol version was set to $ldap_protocol_version")); 116 } 117 } 118 } 119 120 121 // first bind and try to determine the correct dn for the user with uid=$username 122 if (! @ldap_bind($ds, $query_dn, $query_pw)) { 123 array_push($Messages, _("LDAP bind failed."), 124 sprintf(_("Error: %s"),htmlspecialchars(ldap_err2str(ldap_errno($ds))))); 125 if ($debug) { 126 array_push($Messages, 127 htmlspecialchars("LDAP server: $ldap_server"), 128 htmlspecialchars('BIND-DN: ' . (! empty($query_dn) ? $query_dn : 'anonymous'))); 129 } 130 return $Messages; 131 } else { 132 if ($debug) { 133 array_push($Messages, 134 'LDAP bind successful.', 135 htmlspecialchars("LDAP server: $ldap_server"), 136 htmlspecialchars('BIND-DN: ' . (! empty($query_dn) ? $query_dn : 'anonymous'))); 137 } 138 } 139 140 if (!empty($ldap_filter)) { 141 if (!preg_match('/^\\(.+\\)$/',$ldap_filter)) { 142 $ldap_filter = '(' . $ldap_filter . ')'; 143 } 144 $filter = "(&$ldap_filter($ldap_user_field=$username))"; 145 } else { 146 $filter = "($ldap_user_field=$username)"; 147 } 148 149 // Hide ldap_search notices 150 $sr=@ldap_search($ds,$ldap_base_dn,$filter,array('dn')); //search for uid 151 if (! $sr) { 152 array_push($Messages, _("LDAP search failed."), 153 sprintf(_("Error: %s"),htmlspecialchars(ldap_err2str(ldap_errno($ds))))); 154 if ($debug) { 155 array_push($Messages, 156 htmlspecialchars("BASE DN: $ldap_base_dn"), 157 htmlspecialchars("Query: ($ldap_user_field=$username)")); 158 } 159 return $Messages; 160 } 161 162 if (ldap_count_entries($ds,$sr)>1) { 163 array_push($Messages, _("Duplicate login entries detected, cannot change password!")); 164 if ($debug) { 165 array_push($Messages,ldap_debug_print_array(ldap_get_entries($ds,$sr))); 166 } 167 return $Messages; 168 } 169 170 if (ldap_count_entries($ds,$sr)==0) { 171 array_push($Messages, _("Your login account was not found in the LDAP database, cannot change password!")); 172 return $Messages; 173 } 174 175 $info=ldap_get_entries($ds,$sr); 176 if ($debug) { 177 array_push($Messages,ldap_debug_print_array($info)); 178 } 179 $dn=$info[0]["dn"]; //finally get the full users dn 180 181 // now rebind to the database as user to verify password. 182 if (! $no_bind_as_user) { 183 if (! @ldap_bind($ds,$dn,$cp_oldpass)) { //if we can't bind as the user then the old passwd must be wrong 184 array_push($Messages, _("Your old password is not correct.")); 185 if ($debug) { 186 array_push($Messages, 187 'LDAP bind failed.', 188 htmlspecialchars("BIND-DN: $dn")); 189 } 190 return $Messages; 191 } else { 192 if ($debug) { 193 array_push($Messages, 194 'LDAP bind successful.', 195 htmlspecialchars("BIND-DN: $dn")); 196 } 197 } 198 } elseif ($ldap_bind_as_manager) { 199 // Now, if needed, we rebind as the manager so we can read passwords and make changes. 200 if (! @ldap_bind($ds,$ldap_manager_dn,$ldap_manager_pw)) { 201 array_push($Messages, _("LDAP bind failed.")); 202 if ($debug){ 203 array_push($Messages, htmlspecialchars("BIND-DN: $ldap_manager_dn")); 204 } 205 return $Messages; 206 } else { 207 if ($debug) { 208 array_push($Messages, 209 'LDAP bind successful.', 210 htmlspecialchars("BIND-DN: $ldap_manager_dn")); 211 } 212 } 213 } 214 //check the db again, this time so we get the password field returned 215 // (use ldap_read() in order to lookup only located dn entry) 216 $sr=@ldap_read($ds,$dn,"($ldap_user_field=$username)",array('dn',$ldap_password_field,$ldap_user_field,'objectclass')); 217 $info = ldap_get_entries($ds, $sr); 218 if ($debug) { 219 array_push($Messages,ldap_debug_print_array($info)); 220 } 221 222 if (isset($info[0][$ldap_password_field][0])) { 223 $storedpass = $info[0][$ldap_password_field][0]; 224 } else { 225 array_push($Messages, _("We could not retrieve your old password from the LDAP server.")); 226 if ($debug) { 227 array_push($Messages, 228 htmlspecialchars("Configured password field: $ldap_password_field")); 229 } 230 return $Messages; 231 } 232 233 //this next code tries to identify the correct password type 234 //*Note* I've not tested all types here as I cannot reproduce some setups 235 //Please let me know if the code does not work for you, or if you have code that will work 236 //for a particular type. 237 238 //password types: 239 //{crypt} salted passwords of type DES, MD5 and Blowfish 240 //{MD5} unsalted password in MD5 format 241 //{SHA} unsalted password in SHA format 242 //{SMD5} salted md5 243 //{SSHA} salted sha 244 245 //lets try to determine the encrytion method of the stored password 246 $p=split("}",$storedpass); //split the password 247 $ctype=strtolower($p[0]); //into the {crypttype} 248 $lpass=$p[1]; //and the password 249 //if the stored password is {crypt} then its salted, but which sub-type? 250 switch ($ctype) { 251 case "{crypt": 252 $pl=strlen($lpass); // We'll look at the length and salt of what's already stored to determine the crypt sub-type 253 $stype="DES"; //sensible default if not detected 254 if ($pl>=34 and substr($lpass,0,3)=="$1$") $stype="MD5"; 255 if ($pl>=34 and substr($lpass,0,3)=="$2$") $stype="BLOWFISH"; 256 if ($debug) array_push($Messages, _("Password type is") . " {crypt}, sub-type $stype"); 257 $cpass=ldap_crypt_passwd($cp_oldpass,$lpass,$stype); //crypt up our old password so we can check it again 258 break; 259 case "{md5": 260 if ($debug) array_push($Messages, _("Password type is") . " {MD5}" ); 261 $cpass=ldap_md5_passwd($cp_oldpass); 262 break; 263 case "{sha": 264 if ($debug) array_push($Messages, _("Password type is") . " {SHA}"); 265 if (!function_exists('sha1') && ! extension_loaded('mhash')) { 266 array_push($Messages, 267 _("Unsupported password schema. Insufficient PHP version or PHP mhash extension is not available.")); 268 return $Messages; 269 } 270 $cpass=ldap_sha_passwd($cp_oldpass); 271 break; 272 case "{smd5": 273 if ($debug) array_push($Messages, _("Password type is") . " {SMD5}"); 274 $hash = base64_decode($lpass) ; 275 $salt = substr($hash, 16); 276 $cpass = base64_encode(pack("H*", md5($cp_oldpass . $salt)).$salt); 277 break; 278 case "{ssha": 279 if ($debug) array_push($Messages, _("Password type is") . " {SSHA}"); 280 if (!function_exists('sha1') && ! extension_loaded('mhash')) { 281 array_push($Messages, 282 _("Unsupported password schema. Insufficient PHP version or PHP mhash extension is not available.")); 283 return $Messages; 284 } 285 $hash = base64_decode($lpass) ; 286 $salt = substr($hash, 20); 287 $cpass=ldap_ssha_passwd($cp_oldpass,$salt); 288 break; 289 default: // Use plain text password 290 $cpass=$cp_oldpass; 291 $lpass=$storedpass; // Override $lpass as it is truncated from the original 292 break; 293 } 294 //now check again the stored password against the encrypted version of the supplied old password 295 if ($lpass != $cpass) { 296 array_push($Messages, _("Your old password is not correct.")); 297 if ($debug) { 298 array_push($Messages, 299 htmlspecialchars("Stored Password: $lpass"), 300 htmlspecialchars("Old Password: $cpass")); 301 } 302 return $Messages; 303 } 304 //Make sure the new passwd generation uses the encryption method of the previous password 305 switch ($ctype) { 306 case "{crypt": 307 $newpass="{crypt}".ldap_crypt_passwd($cp_newpass,ldap_generate_salt($stype),$stype); 308 break; 309 case "{md5": 310 $newpass="{MD5}".ldap_md5_passwd($cp_newpass); 311 break; 312 case "{sha": 313 $newpass="{SHA}".ldap_sha_passwd($cp_newpass); 314 break; 315 case "{smd5": 316 $newpass="{SMD5}".ldap_smd5_passwd($cp_newpass); 317 break; 318 case "{ssha": 319 $newpass="{SSHA}".ldap_ssha_passwd($cp_newpass); 320 break; 321 // more password types should go here ;-) and the functions to drive them below. 322 default: // Use plain text password 323 $newpass=$cp_newpass; 324 break; 325 } 326 if ($debug) { 327 array_push($Messages, htmlspecialchars("New Password: $newpass")); 328 } 329 330 $newinfo=array(); 331 $newinfo[$ldap_password_field][0]=$newpass; 332 333 if (isset($info[0]['objectclass'])) { 334 $objects = $info[0]['objectclass']; 335 array_walk($objects,'lcp_arraytolower'); 336 } else { 337 // failsafe for missing objectclass data 338 $objects = array(); 339 } 340 if ($change_ldapsmb && in_array($ldapsmb_object,$objects) && 341 ($force_smb_sync || sqgetGlobalVar('sync_smb_pass',$sync_smb_pass,SQ_POST))) { 342 $exe = "$mkntpwd " . escapeshellarg($cp_newpass) . " 2>&1" ; 343 if ($debug) array_push($Messages,$exe); 344 $retarray = array(); 345 $retval = 1; 346 $ntString = exec($exe, $retarray, $retval); 347 if ($debug) $Messages = array_merge($Messages,$retarray); 348 if ( $retval == "0" && preg_match("/^[0-9A-F]+:[0-9A-F]+$/",$ntString )) { 349 list($lmPassword, $ntPassword) = explode (":", $ntString); 350 $newinfo[$ldapsmb_ntpassword] = $ntPassword; 351 $newinfo[$ldapsmb_lmpassword] = $lmPassword; 352 } else { // could not generate ntlm passwords 353 array_push($Messages,_("Could not generate NTLM password hashes!")); 354 if (!empty($retarray)) { 355 $retmsg = implode("\n",$retarray); 356 array_push($Messages,sprintf(_("Error: %s"),htmlspecialchars($retmsg))); 357 } 358 return $Messages; 359 } 360 } 361 362 if (@ldap_modify($ds,$dn,$newinfo)) { 363 $smb=0; 364 if ($change_smb && 365 ($force_smb_sync || sqgetGlobalVar('sync_smb_pass',$sync_smb_pass,SQ_POST))) { 366 // First we print three lines in stdin 367 $exe = 'echo -e ' . escapeshellarg($cp_oldpass . "\\n" . $cp_newpass . "\\n" . $cp_newpass); 368 // then pipe to smbpasswd 369 $exe.= " | $smb_passwd "; 370 // add remote machine name 371 if (!empty($smb_host)) { 372 $exe.= '-r ' . escapeshellarg($smb_host); 373 } 374 // add username, get passwords from stdin (-s), redirect output to stdout 375 $exe.= " -U " . escapeshellarg($username) 376 . " -s 2>&1"; 377 378 // Save used command for debugging 379 if ($debug) { 380 array_push($Messages,$exe); 381 } 382 383 // initial values 384 $retarr = array(); 385 $retval = 1; 386 // exec returns last line, but we don't need it. Same line is stored in $retarr 387 exec($exe,$retarr,$retval); 388 // Check $retval. 0 = success, 1 = failure 389 if ($retval) { 390 // push $retarr to $Messages 391 foreach($retarr as $retline) { 392 array_push($Messages, htmlspecialchars($retline)); 393 } 394 } else { 395 $smb=1 ; 396 if ($debug) { 397 foreach($retarr as $retline) { 398 array_push($Messages, htmlspecialchars($retline)); 399 } 400 } 401 } 402 } else { 403 $smb=1; 404 } 405 if ($smb) { 406 // load sqm_baseuri() function for SM 1.4.0-1.4.5 407 include_once(SM_PATH . 'functions/display_messages.php'); 408 $base_uri = sqm_baseuri(); 409 // Write new cookies for the password 410 $onetimepad = OneTimePadCreate(strlen($cp_newpass)); 411 $_SESSION['onetimepad']=$onetimepad; //do I need to do this now? 412 $key = OneTimePadEncrypt($cp_newpass, $onetimepad); 413 $_COOKIES['key']=$key; 414 setcookie("key", $key, 0, $base_uri); 415 // Give feedback if password change was successful. 416 if (! $debug) { 417 array_push($Messages, _("Password changed successfully")); 418 return $Messages ; 419 } 420 return $Messages; 421 } else { //smbpasswd change failed so we must re sync the ldap password back to its original 422 $newinfo[$ldap_password_field][0]=$storedpass; 423 if (@ldap_modify($ds,$dn,$newinfo)) { 424 array_push($Messages, _("SMB Password change was not successful, so LDAP not changed!")); 425 } else { 426 array_push($Messages, _("Due to numerous password modification errors your LDAP and SMB passwords are out of sync. Please contact your administrator.")); 427 } 428 return $Messages; 429 } 430 } else { 431 array_push($Messages, _("LDAP Password change was not successful!")); 432 if ($debug) array_push($Messages, _("LDAP ERROR => " . ldap_error($ds))) ; 433 return $Messages; 434 } 435} 436 437// Generate an unsalted SHA1 pw. This should work withNetscape messaging / directory server 4+ 438function ldap_sha_passwd($clear_pw) { 439 if(function_exists('sha1')) { 440 $hash = pack("H*",sha1($clear_pw)); 441 } else if (function_exists('mHash')) { 442 $hash = mHash(MHASH_SHA1, $clear_pw); 443 } else { 444 echo "Error: You will need php >= 4.3.0 or php compiled with MHASH if you are going to use SHA or SSHA passwords."; 445 exit(); 446 } 447 return base64_encode($hash); 448} 449 450/** 451 * Generate a salted SHA1 pw. 452 * @param string $clean_pw 453 * @param string $salt 454 * @return string 455 */ 456function ldap_ssha_passwd($clear_pw,$salt=null) { 457 if (!isset($salt)){ 458 // set seed for the random number generator 459 mt_srand((double)microtime()*1000000); 460 $salt = substr(md5(mt_rand()), 4, 8); 461 } 462 if(function_exists('sha1')) { 463 $hash = pack("H*",sha1($clear_pw . $salt)); 464 } else if (function_exists('mHash')) { 465 $hash = mHash(MHASH_SHA1, $clear_pw . $salt); 466 } else { 467 echo "Error: You will need php >= 4.3.0 or php compiled with MHASH if you are going to use SHA or SSHA passwords."; 468 exit(); 469 } 470 return base64_encode($hash . $salt); 471} 472 473// Generate an unsalted MD5 pw. This works fine with OpenLDAP. 474function ldap_md5_passwd($clear_pw) { 475 return base64_encode(pack("H*", md5($clear_pw))); 476} 477 478function ldap_smd5_passwd($clear_pw) { 479 $salt = myhash_keyge_s2k($clear_pw, 4); 480 $new_password = base64_encode(pack("H*", md5($clear_pw . $salt)) . $salt); 481 return $new_password ; 482} 483 484/** 485 * Generates salted crypt passwords 486 * 487 * @param string $password 488 * @param string $salt 489 * @param string $stype Password type. MD5, BLOWFISH, DES. If other string is 490 * used, since 2.2 function defaults to DES. 491 * @return string 492 */ 493function ldap_crypt_passwd($password,$salt,$stype) { 494 if ($stype=="MD5") return crypt($password,substr($salt,0,12)); //MD5 uses 12 chr salt 495 if ($stype=="BLOWFISH") return crypt($password,substr($salt,0,16)); //BLOWFISH uses 16 chr salt 496 // DES or something else 497 return crypt($password,substr($salt,0,2)); //crypt uses 2 chr salt 498} 499 500/** 501 * Generates salt 502 * @param string $stype Salt type. MD5, BLOWFISH or DES. If other string is 503 * used, since 2.2 function defaults to DES. 504 * @return string Salt string 505 */ 506function ldap_generate_salt($stype) { 507 $salt=""; //generate a salt using characters [A-Z][a-z][0-9]./ 508 $chars="./0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; 509 for ($i=0;$i<16;$i++) { 510 $salt.=$chars[mt_rand(0,strlen($chars))]; 511 } 512 //return salts longer than we need but these will be trimmed in the ldap_crypt_passwd function 513 if ($stype=="MD5") return "$1$".$salt; 514 if ($stype=="BLOWFISH") return "$2$".$salt; 515 // DES or something else 516 return $salt; 517} 518 519/** 520 * This and md5 implimentation of the Salted S2K algorithm as 521 * specified in the OpenPGP document (RFC 2440). 522 * basically a non mhash dependant version of mhash_keygen_s2k 523 * @param string $pass 524 * @param integer $bytes 525 * @return string 526 */ 527function myhash_keyge_s2k($pass, $bytes ){ 528 $salt=substr(pack("h*", md5(mt_rand())), 0, 8); 529 return substr(pack("H*", md5($salt . $pass)), 0, $bytes); 530} 531 532/** 533 * Debug function used to print ldap search results 534 * @param array $array 535 */ 536function ldap_debug_print_array($array) { 537 $out="<br>--------------------------------------------------------<br>\n"; 538 $out.=ldap_debug_print_array1($array,""); 539 $out.= "<br>--------------------------------------------------------<br>\n"; 540 return $out; 541} 542 543/** 544 * Prints array recursively 545 * @param mixed $array 546 * @param string $out 547 * @return string 548 */ 549function ldap_debug_print_array1($array,$out) { 550 if(gettype($array)=="array") { 551 $out.="<ul>"; 552 while (list($index, $subarray) = each($array) ) { 553 $out.='<li>' . htmlspecialchars($index) . " <code>=></code>"; 554 $out=ldap_debug_print_array1($subarray,$out); 555 $out.="</li>"; 556 } 557 $out.="</ul>"; 558 } else { 559 $out.=htmlspecialchars($array); 560 } 561 return $out; 562} 563 564/** 565 * Translates PHP Crack extension messages 566 * 567 * cpw_translate_crack_msg() function from NaSMail change_password plugin. 568 * @param string $err error from crack_getlastmessage() 569 * @return string translated error message or original error 570 * @since 2.2 571 */ 572function lcp_translate_crack_msg($err) { 573 /** 574 * PHP crack 0.4 extension errors 575 * from cracklib_fascist_look_ex() 576 * - it's WAY too short 577 * - it is too short 578 * - it is too simplistic/systematic 579 * - it looks like a National Insurance number. 580 * - it is all whitespace 581 * - it does not contain enough DIFFERENT characters 582 * - it is based on a dictionary word 583 * - it is based on a (reversed) dictionary word 584 * from cracklib_fascist_gecos() (checks are not executed on Win32) 585 * - you are not registered in the password file 586 * - it is based on your username 587 * - it's derivable from your password entry 588 * - it is derivable from your password entry 589 * - it is derived from your password entry 590 * - it's derived from your password entry 591 * - it is based upon your password entry 592 */ 593 594 // can't use strcasecmp(). No locale insensitive string comparison functions in PHP. 595 // internal implementation will slow things down. 596 switch($err) { 597 case 'it\'s WAY too short': 598 case 'it is too short': 599 $err = _("Password is too short."); 600 break; 601 case 'it is too simplistic/systematic': 602 $err = _("New password is too simplistic/systematic."); 603 break; 604 case 'it looks like a National Insurance number.': 605 // password looks like personal identification number used 606 // in UK's social security system (aa000000a). 607 $err = _("New password looks like a National Insurance number."); 608 break; 609 case 'it is all whitespace': 610 $err = _("New password contains only whitespace."); 611 break; 612 case 'it does not contain enough DIFFERENT characters': 613 $err = _("New password does not contain enough DIFFERENT characters."); 614 break; 615 case 'it is based on a dictionary word': 616 $err = _("New password is based on a dictionary word."); 617 break; 618 case 'it is based on a (reversed) dictionary word': 619 $err = _("New password is based on a (reversed) dictionary word."); 620 break; 621 case 'you are not registered in the password file': 622 $err = _("You are not registered in the password file."); 623 break; 624 case 'it is based on your username': 625 $err = _("New password is based on your username."); 626 break; 627 case 'it\'s derivable from your password entry': 628 case 'it is derivable from your password entry': 629 case 'it is derived from your password entry': 630 case 'it\'s derived from your password entry': 631 case 'it is based upon your password entry': 632 // combines five error messages. 633 // password is derivable/derived/based upon your password entry 634 $err = _("New password is similar to your current password entry."); 635 break; 636 default: 637 // leave $err untranslated 638 } 639 // 'No obscure checks in this session' - error comes from PHP crack extension 640 // should never pop out because we always call crack_check() before crack_getlastmessage() 641 return $err; 642} 643 644/** 645 * Callback function to lowercase array keys and values 646 * 647 * See ldq_arraytolower in ldapquery plugin. 648 * @param string Array value 649 * @param string Array key 650 * @since 2.2 651 */ 652function lcp_arraytolower(&$value,&$key) { 653 $value=strtolower($value); 654 $key=strtolower($key); 655} 656