getConfig('ldap_options.displayClearValue', false, 'bool')) { if (is_array($data)) { $ret=array(); $wildcardPassword = $this -> getConfig('ldap_options.wildcardPassword'); $encodedWildcardPassword = $this -> getConfig('ldap_options.encodedWildcardPassword'); foreach($data as $p) { if ($p == $wildcardPassword || $p == $encodedWildcardPassword) { continue; } $ret[]=$p; } return $ret; } else { return $data; } } else { return '********'; } } /** * Return the value of this attribute to be stocked * * Note : Password encoding was strongly inspired of the project phpLdapAdmin. * URL : http://phpldapadmin.sourceforge.net/ * * @param[in] $data mixed The attribute value * * @retval mixed The value of this attribute to be stocked */ public function getUpdateData($data) { $this -> clearPassword = $data[0]; $data=array(); $data[]=$this -> encodePassword($this -> clearPassword); // Wildcard Password $wildcardPassword = $this -> getConfig('ldap_options.wildcardPassword'); if ($wildcardPassword) { if (!is_array($wildcardPassword)) { $data[] = $this -> encodePassword($wildcardPassword); } else { foreach($wildcardPassword as $pwd) { $data[] = $this -> encodePassword($pwd); } } } // Wildcard Password already encoded $encodedWildcardPassword = $this -> getConfig('ldap_options.encodedWildcardPassword'); if ($encodedWildcardPassword) { if (!is_array($encodedWildcardPassword)) { $data[] = $encodedWildcardPassword; } else { $data = array_merge($data, $encodedWildcardPassword); } } return $data; } /** * Encode the password * * Note : Password encoding was strongly inspired of the project phpLdapAdmin. * URL : http://phpldapadmin.sourceforge.net/ * * @param[in] $clearPassword string The clear password * * @retval strinf The encode password */ public function encodePassword($clearPassword, $encode=null, $encode_function=null, $salt=null) { if (is_null($encode)) $encode = $this -> getConfig('ldap_options.encode', 'md5crypt', 'string'); if (is_null($encode_function)) $encode_function = $this -> getConfig('ldap_options.encode_function'); if ($encode_function || $encode == 'function') { if ( (!$encode_function) || (!is_callable($encode_function)) ) { $encode = 'clear'; $encode_function = null; LSerror :: addErrorCode('LSattr_ldap_password_02', ($encode_function?$encode_function:__('undefined'))); } else { $encode = 'function'; } } switch($encode) { case 'crypt': if ($this -> getConfig('ldap_options.no_random_crypt_salt')) { return '{CRYPT}' . crypt($clearPassword,substr($clearPassword,0,2)); } else { if (is_null($salt)) $salt = $this -> getSalt(2); return '{CRYPT}' . crypt($clearPassword, $salt); } break; case 'ext_des': if ( ! defined( 'CRYPT_EXT_DES' ) || CRYPT_EXT_DES == 0 ) { LSerror :: addErrorCode('LSattr_ldap_password_01','ext_des'); } else { if (is_null($salt)) $salt = $this -> getSalt(8); return '{CRYPT}' . crypt( $clearPassword, '_' . $salt ); } break; case 'blowfish': if( ! defined( 'CRYPT_BLOWFISH' ) || CRYPT_BLOWFISH == 0 ) { LSerror :: addErrorCode('LSattr_ldap_password_01','blowfish'); } else { if (is_null($salt)) $salt = '$2y$12$' . $this -> getSalt(22); return '{CRYPT}' . crypt( $clearPassword, $salt ); } break; case 'sha': if( function_exists('sha1') ) { return '{SHA}' . base64_encode( pack( 'H*' , sha1( $clearPassword ) ) ); } elseif( function_exists( 'mhash' ) ) { return '{SHA}' . base64_encode( mhash( MHASH_SHA1, $clearPassword ) ); } else { LSerror :: addErrorCode('LSattr_ldap_password_01','sha'); } break; case 'sha256': case 'sha512': switch($encode) { case 'sha256': $mhash_type = MHASH_SHA256; break; case 'sha512': $mhash_type = MHASH_SHA512; break; } if( function_exists( 'mhash' ) ) { return '{'.strtoupper($encode).'}' . base64_encode( mhash( $mhash_type, $clearPassword ) ); } else { LSerror :: addErrorCode('LSattr_ldap_password_01', $encode); } break; case 'ssha': case 'ssha256': case 'ssha512': switch($encode) { case 'ssha': $mhash_type = MHASH_SHA1; break; case 'ssha256': $mhash_type = MHASH_SHA256; break; case 'ssha512': $mhash_type = MHASH_SHA512; break; } if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) { mt_srand( (double) microtime() * 1000000 ); if (is_null($salt)) $salt = mhash_keygen_s2k( $mhash_type, $clearPassword, substr( pack( "h*", md5( mt_rand() ) ), 0, 8 ), 4 ); return "{".strtoupper($encode)."}".base64_encode( mhash( $mhash_type, $clearPassword.$salt ).$salt ); } else { LSerror :: addErrorCode('LSattr_ldap_password_01', $encode); } break; case 'smd5': if( function_exists( 'mhash' ) && function_exists( 'mhash_keygen_s2k' ) ) { mt_srand( (double) microtime() * 1000000 ); if (is_null($salt)) $salt = mhash_keygen_s2k( MHASH_MD5, $password_clear, substr( pack( "h*", md5( mt_rand() ) ), 0, 8 ), 4 ); return "{SMD5}".base64_encode( mhash( MHASH_MD5, $clearPassword.$salt ).$salt ); } else { LSerror :: addErrorCode('LSattr_ldap_password_01','smd5'); } break; case 'md5': return '{MD5}' . base64_encode( pack( 'H*' , md5( $clearPassword ) ) ); break; case 'md5crypt': if( ! defined( 'CRYPT_MD5' ) || CRYPT_MD5 == 0 ) { LSerror :: addErrorCode('LSattr_ldap_password_01','md5crypt'); } else { if (is_null($salt)) $salt = $this -> getSalt(); return '{CRYPT}'.crypt($clearPassword,'$1$'.$salt.'$'); } break; case 'clear': return $clearPassword; break; case 'function': return call_user_func_array($encode_function, array(&$this -> attribute -> ldapObject, $clearPassword)); break; } LSerror :: addErrorCode('LSattr_ldap_password_01', $encode); return $clearPassword; } function verify($clearPassword, $hashedPassword=null) { // If $hashedPassword is not provided, use attribute values if (is_null($hashedPassword)) $hashedPassword = $this -> attribute -> getValue(); // If $hashedPassword is array, iter to find valid password if (is_array($hashedPassword)) { foreach($hashedPassword as $pwd) if ($this -> verify($clearPassword, $pwd)) return true; return false; } // Verify $hashedPassword is a string elseif (!is_string($hashedPassword)) return false; // Custom verify function configured ? If yes, use it $verifyFunction = $this -> getConfig('ldap_options.verify_function', null); if (!is_null($verifyFunction) && is_callable($verifyFunction)) return call_user_func($verifyFunction, $clearPassword, $hashedPassword); // Custom encode function configured ? If yes, use it $encodeFunction = $this -> getConfig('ldap_options.encode_function', null); if (!is_null($encodeFunction) && is_callable($encodeFunction)) return (strcasecmp(call_user_func_array($encodeFunction, array(&$this -> attribute -> ldapObject, $clearPassword)), $hashedPassword) == 0); // Extract cipher if (preg_match('/{([^}]+)}(.*)/',$hashedPassword,$matches)) { $hashedPasswordData = $matches[2]; $cypher = strtolower($matches[1]); } else { $cypher = null; } // Verify password according on cypher switch($cypher) { # SSHA crypted passwords case 'ssha': case 'ssha256': case 'ssha512': case 'smd5': $data = base64_decode($hashedPasswordData); # Salt = last 4 bytes $salt = substr($data, -4); $new_hash = $this -> encodePassword($clearPassword, $cypher, null, $salt); return (strcmp($hashedPassword,$new_hash) == 0); break; # Non-salted cyphers case 'sha': case 'sha256': case 'sha512': case 'md5': $new_hash = $this -> encodePassword($clearPassword, $cypher); return (strcasecmp($new_hash, $hashedPassword) == 0); break; # Crypt passwords case 'crypt': # Check if it's blowfish crypt if (preg_match('/^\\$2+/',$hashedPasswordData)) { list($dummy, $version, $rounds, $salt_hash) = explode('$',$hashedPasswordData); $salt = '$'.$version.'$'.$rounds.'$'.substr($salt_hash, 0, 22); $new_hash = $this -> encodePassword($clearPassword, 'blowfish', null, $salt); return (strcasecmp($new_hash, $hashedPassword) == 0); } # Check if it's an md5crypt elseif (strstr($hashedPasswordData,'$1$')) { list($dummy,$type,$salt,$hash) = explode('$',$hashedPasswordData); $new_hash = $this -> encodePassword($clearPassword, 'md5crypt', null, $salt); return (strcasecmp($new_hash, $hashedPassword) == 0); } # Check if it's ext_des crypt elseif (strstr($hashedPasswordData,'_')) { return (crypt($clearPassword,$hashedPasswordData) == $hashedPasswordData); } # Password is plain crypt else { return (crypt($clearPassword,$hashedPasswordData) == $hashedPasswordData); } break; # No crypt is given default: # Assume is a plaintext password return (strcasecmp($clearPassword, $hashedPassword) == 0); } // It's supposed to never append, but just in case, return false return false; } /** * Return salt (random string) * * @param[in] integer Number of caracters in this salt * * @retval string A salt */ public static function getSalt($length=8) { $pattern = "1234567890abcdefghijklmnopqrstuvwxyz"; $key = $pattern{rand(0,35)}; for($i=1;$i<$length;$i++) { $key .= $pattern{rand(0,35)}; } return $key; } /** * Return the password in clear text * * @retval string The password in clear text */ public function getClearPassword() { return $this -> clearPassword; } } /** * Error Codes **/ LSerror :: defineError('LSattr_ldap_password_01', _("LSattr_ldap_password : Encoding type %{type} is not supported. This password will be stored in clear text.") ); LSerror :: defineError('LSattr_ldap_password_02', _("LSattr_ldap_password : Encoding function %{function} is not callable. This password will be stored in clear text.") );