Source for file ldap.php

Documentation is available at ldap.php

  1. <?php
  2.  
  3. /**
  4.  * Change password LDAP backend
  5.  *
  6.  * @copyright 2005-2020 The SquirrelMail Project Team
  7.  * @license http://opensource.org/licenses/gpl-license.php GNU Public License
  8.  * @version $Id: ldap.php 14845 2020-01-07 08:09:34Z pdontthink $
  9.  * @package plugins
  10.  * @subpackage change_password
  11.  */
  12.  
  13. /**
  14.  * do not allow to call this file directly
  15.  */
  16. if (isset($_SERVER['SCRIPT_FILENAME']&& $_SERVER['SCRIPT_FILENAME'== __FILE__{
  17.     header("Location: ../../../src/login.php");
  18.     die();
  19. }
  20.  
  21. /** load required functions */
  22.  
  23. /** sqimap_get_user_server() function */
  24. include_once(SM_PATH 'functions/imap_general.php');
  25.  
  26. /** get imap server and username globals */
  27. global $imapServerAddress$username;
  28.  
  29. /** Default plugin configuration.*/
  30. /**
  31.  * Address of LDAP server.
  32.  * You can use any URL format that is supported by your LDAP extension.
  33.  * Examples:
  34.  * <ul>
  35.  *   <li>'ldap.example.com' - connect to server on ldap.example.com address
  36.  *   <li>'ldaps://ldap.example.com' - connect to server on ldap.example.com address
  37.  *   and use SSL encrypted connection to default LDAPs port.
  38.  * </ul>
  39.  * defaults to imap server address.
  40.  * @link http://www.php.net/ldap-connect
  41.  * @global string $cpw_ldap_server 
  42.  */
  43. global $cpw_ldap_server;
  44. $cpw_ldap_server=$imapServerAddress;
  45.  
  46. /**
  47.  * Port of LDAP server.
  48.  * Used only when $cpw_ldap_server specifies IP address or DNS name.
  49.  * @global integer $cpw_ldap_port 
  50.  */
  51. global $cpw_ldap_port;
  52. $cpw_ldap_port=389;
  53.  
  54. /**
  55.  * LDAP basedn that is used for binding to LDAP server.
  56.  * this option must be set to correct value.
  57.  * @global string $cpw_ldap_basedn; 
  58.  */
  59. global $cpw_ldap_basedn;
  60. $cpw_ldap_basedn='';
  61.  
  62. /**
  63.  * LDAP connection options
  64.  * @link http://www.php.net/ldap-set-option
  65.  * @global array $cpw_ldap_connect_opts 
  66.  */
  67. global $cpw_ldap_connect_opts;
  68. $cpw_ldap_connect_opts=array();
  69.  
  70. /**
  71.  * Controls use of starttls on LDAP connection.
  72.  * Requires PHP 4.2+, PHP LDAP extension with SSL support and
  73.  * PROTOCOL_VERSION => 3 setting in $cpw_ldap_connect_opts
  74.  * @global boolean $cpw_ldap_use_tls 
  75.  */
  76. global $cpw_ldap_use_tls;
  77. $cpw_ldap_use_tls=false;
  78.  
  79. /**
  80.  * BindDN that should be able to search LDAP directory and find DN used by user.
  81.  * Uses anonymous bind if set to empty string. You should not use DN with write
  82.  * access to LDAP directory here. Write access is not required.
  83.  * @global string $cpw_ldap_binddn 
  84.  */
  85. global $cpw_ldap_binddn;
  86. $cpw_ldap_binddn='';
  87.  
  88. /**
  89.  * password used for $cpw_ldap_binddn
  90.  * @global string $cpw_ldap_bindpw 
  91.  */
  92. global $cpw_ldap_bindpw;
  93. $cpw_ldap_bindpw='';
  94.  
  95. /**
  96.  * BindDN that should be able to change password.
  97.  * WARNING: sometimes user has enough privileges to change own password.
  98.  * If you leave default value, plugin will try to connect with DN that
  99.  * is detected in $cpw_ldap_username_attr=$username search and current
  100.  * user password will be used for authentication.
  101.  * @global string $cpw_ldap_admindn 
  102.  */
  103. global $cpw_ldap_admindn;
  104. $cpw_ldap_admindn='';
  105.  
  106. /**
  107.  * password used for $cpw_ldap_admindn
  108.  * @global string $cpw_ldap_adminpw 
  109.  */
  110. global $cpw_ldap_adminpw;
  111. $cpw_ldap_adminpw='';
  112.  
  113. /**
  114.  * LDAP attribute that stores username.
  115.  * username entry should be unique for $cpw_ldap_basedn
  116.  * @global string $cpw_ldap_userid_attr 
  117.  */
  118. global $cpw_ldap_userid_attr;
  119. $cpw_ldap_userid_attr='uid';
  120.  
  121. /**
  122.  * crypto that is used to encode new password
  123.  * If set to empty string, system tries to keep same encoding/hashing algorithm
  124.  * @global string $cpw_ldap_default_crypto 
  125.  */
  126. global $cpw_ldap_default_crypto;
  127. $cpw_ldap_default_crypto='';
  128.  
  129. /** end of default config */
  130.  
  131. /** configuration overrides from config file */
  132. if (isset($cpw_ldap['server'])) $cpw_ldap_server=$cpw_ldap['server'];
  133. if (isset($cpw_ldap['port'])) $cpw_ldap_port=$cpw_ldap['port'];
  134. if (isset($cpw_ldap['basedn'])) $cpw_ldap_basedn=$cpw_ldap['basedn'];
  135. if (isset($cpw_ldap['connect_opts'])) $cpw_ldap_connect_opts=$cpw_ldap['connect_opts'];
  136. if (isset($cpw_ldap['use_tls'])) $cpw_ldap_use_tls=$cpw_ldap['use_tls'];
  137. if (isset($cpw_ldap['binddn'])) $cpw_ldap_binddn=$cpw_ldap['binddn'];
  138. if (isset($cpw_ldap['bindpw'])) $cpw_ldap_bindpw=$cpw_ldap['bindpw'];
  139. if (isset($cpw_ldap['admindn'])) $cpw_ldap_admindn=$cpw_ldap['admindn'];
  140. if (isset($cpw_ldap['adminpw'])) $cpw_ldap_adminpw=$cpw_ldap['adminpw'];
  141. if (isset($cpw_ldap['userid_attr'])) $cpw_ldap_userid_attr=$cpw_ldap['userid_attr'];
  142. if (isset($cpw_ldap['default_crypto'])) $cpw_ldap_default_crypto=$cpw_ldap['default_crypto'];
  143.  
  144. /** make sure that setting does not contain mapping */
  145. $cpw_ldap_server=sqimap_get_user_server($cpw_ldap_server,$username);
  146.  
  147. /**
  148.  * Adding plugin hooks
  149.  */
  150. global $squirrelmail_plugin_hooks;
  151. $squirrelmail_plugin_hooks['change_password_dochange']['ldap'=
  152.         'cpw_ldap_dochange';
  153. $squirrelmail_plugin_hooks['change_password_init']['ldap'=
  154.         'cpw_ldap_init';
  155.  
  156. /**
  157.  * Makes sure that required functions and configuration options are set.
  158.  */
  159. function cpw_ldap_init({
  160.     global $oTemplate$cpw_ldap_basedn;
  161.  
  162.     // set initial value for error tracker
  163.     $cpw_ldap_initerr=false;
  164.  
  165.     // check for ldap support in php
  166.     if (function_exists('ldap_connect')) {
  167.         error_box(_("Current configuration requires LDAP support in PHP."));
  168.         $cpw_ldap_initerr=true;
  169.     }
  170.  
  171.     // chech required configuration settings.
  172.     if ($cpw_ldap_basedn==''{
  173.         error_box(_("Plugin is not configured correctly."));
  174.         $cpw_ldap_initerr=true;
  175.     }
  176.  
  177.     // if error var is positive, close html and stop execution
  178.     if ($cpw_ldap_initerr{
  179.         $oTemplate->display('footer.tpl');
  180.         exit;
  181.     }
  182. }
  183.  
  184.  
  185. /**
  186.  * Changes password. Main function attached to hook
  187.  * @param array $data The username/curpw/newpw data.
  188.  * @return array Array of error messages.
  189.  */
  190. function cpw_ldap_dochange($data{
  191.     global $cpw_ldap_server$cpw_ldap_port$cpw_ldap_basedn,
  192.  
  193.     // unfortunately, we can only pass one parameter to a hook function,
  194.     // so we have to pass it as an array.
  195.     $username $data['username'];
  196.     $curpw $data['curpw'];
  197.     $newpw $data['newpw'];
  198.  
  199.     // globalize current password.
  200.  
  201.     $msgs array();
  202.  
  203.     /**
  204.      * connect to LDAP server
  205.      * hide ldap_connect() function call errors, because they are processed in script.
  206.      * any script execution error is treated as critical, error messages are dumped
  207.      * to $msgs and LDAP connection is closed with ldap_unbind(). all ldap_unbind()
  208.      * errors are suppressed. Any other error suppression should be explained.
  209.      */
  210.     $cpw_ldap_con=@ldap_connect($cpw_ldap_server);
  211.  
  212.     if ($cpw_ldap_con{
  213.         $cpw_ldap_con_err=false;
  214.  
  215.         // set connection options
  216.         if (is_array($cpw_ldap_connect_opts&& $cpw_ldap_connect_opts!=array()) {
  217.             // ldap_set_option() is available only with openldap 2.x and netscape directory sdk.
  218.             if (function_exists('ldap_set_option')) {
  219.                 foreach ($cpw_ldap_connect_opts as $opt => $value{
  220.                     // Make sure that constant is defined defore using it.
  221.                     if (defined('LDAP_OPT_' $opt)) {
  222.                         // ldap_set_option() should not produce E_NOTICE or E_ALL errors and does not modify ldap_error().
  223.                         // leave it without @ in order to see any weird errors
  224.                         if (ldap_set_option($cpw_ldap_con,constant('LDAP_OPT_' $opt),$value)) {
  225.                             // set error message
  226.                             array_push($msgs,sprintf(_("Setting of LDAP connection option %s to value %s failed."),$opt,$value));
  227.                             $cpw_ldap_con_err=true;
  228.                         }
  229.                     else {
  230.                         array_push($msgs,sprintf(_("Incorrect LDAP connection option: %s"),$opt));
  231.                         $cpw_ldap_con_err=true;
  232.                     }
  233.                 }
  234.             else {
  235.                 array_push($msgs,_("Current PHP LDAP extension does not allow use of ldap_set_option() function."));
  236.                 $cpw_ldap_con_err=true;
  237.             }
  238.         }
  239.  
  240.         // check for connection errors and stop execution if something is wrong
  241.         if ($cpw_ldap_con_err{
  242.             @ldap_unbind($cpw_ldap_con);
  243.             return $msgs;
  244.         }
  245.  
  246.         // enable ldap starttls
  247.         if ($cpw_ldap_use_tls &&
  248.             check_php_version(4,2,0&&
  249.             isset($cpw_ldap_connect_opts['PROTOCOL_VERSION']&&
  250.             $cpw_ldap_connect_opts['PROTOCOL_VERSION']>=&&
  251.             function_exists('ldap_start_tls')) {
  252.             // suppress ldap_start_tls errors and process error messages
  253.             if (@ldap_start_tls($cpw_ldap_con)) {
  254.                 array_push($msgs,
  255.                            _("Unable to use TLS."),
  256.                            sprintf(_("Error: %s"),ldap_error($cpw_ldap_con)));
  257.                 $cpw_ldap_con_err=true;
  258.             }
  259.         elseif ($cpw_ldap_use_tls{
  260.             array_push($msgs,_("Unable to use LDAP TLS in current setup."));
  261.             $cpw_ldap_con_err=true;
  262.         }
  263.  
  264.         // check for connection errors and stop execution if something is wrong
  265.         if ($cpw_ldap_con_err{
  266.             @ldap_unbind($cpw_ldap_con);
  267.             return $msgs;
  268.         }
  269.  
  270.         /**
  271.          * Bind to LDAP (use anonymous bind or unprivileged DN) in order to get user's DN
  272.          * hide ldap_bind() function call errors, because errors are processed in script
  273.          */
  274.         if ($cpw_ldap_binddn!=''{
  275.             // authenticated bind
  276.             $cpw_ldap_binding=@ldap_bind($cpw_ldap_con,$cpw_ldap_binddn,$cpw_ldap_bindpw);
  277.         else {
  278.             // anonymous bind
  279.             $cpw_ldap_binding=@ldap_bind($cpw_ldap_con);
  280.         }
  281.  
  282.         // check ldap_bind errors
  283.         if ($cpw_ldap_binding{
  284.             array_push($msgs,
  285.                        _("Unable to bind to LDAP server."),
  286.                        sprintf(_("Server replied: %s"),ldap_error($cpw_ldap_con)));
  287.             @ldap_unbind($cpw_ldap_con);
  288.             return $msgs;
  289.         }
  290.  
  291.         // find userdn
  292.         $cpw_ldap_search_err=cpw_ldap_uid_search($cpw_ldap_con,$cpw_ldap_basedn,$msgs,$cpw_ldap_res,$cpw_ldap_userdn);
  293.  
  294.         // check for search errors and stop execution if something is wrong
  295.         if ($cpw_ldap_search_err{
  296.             @ldap_unbind($cpw_ldap_con);
  297.             return $msgs;
  298.         }
  299.  
  300.         /**
  301.          * unset $cpw_ldap_res2 variable, if such var exists.
  302.          * $cpw_ldap_res2 object can be set in two places and second place checks,
  303.          * if object was created in first place. if variable name matches (somebody
  304.          * uses $cpw_ldap_res2 in code or globals), incorrect validation might
  305.          * cause script errors.
  306.          */
  307.         if (isset($cpw_ldap_res2)) unset($cpw_ldap_res2);
  308.  
  309.         // rebind as userdn or admindn
  310.         if ($cpw_ldap_admindn!=''{
  311.             // admindn bind
  312.             $cpw_ldap_binding=@ldap_bind($cpw_ldap_con,$cpw_ldap_admindn,$cpw_ldap_adminpw);
  313.  
  314.             if ($cpw_ldap_binding{
  315.                 // repeat search in order to get password info. Password info should be unavailable in unprivileged bind.
  316.                 $cpw_ldap_search_err=cpw_ldap_uid_search($cpw_ldap_con,$cpw_ldap_basedn,$msgs,$cpw_ldap_res2,$cpw_ldap_userdn);
  317.  
  318.                 // check for connection errors and stop execution if something is wrong
  319.                 if ($cpw_ldap_search_err{
  320.                     @ldap_unbind($cpw_ldap_con);
  321.                     // errors are added to msgs by cpw_ldap_uid_search()
  322.                     return $msgs;
  323.                 }
  324.  
  325.                 // we should check user password here.
  326.                 // suppress errors and check value returned by function call
  327.                 $cpw_ldap_cur_pass_array=@ldap_get_values($cpw_ldap_con,
  328.                                                          ldap_first_entry($cpw_ldap_con,$cpw_ldap_res2),'userpassword');
  329.  
  330.                 // check if ldap_get_values() have found userpassword field
  331.                 if ($cpw_ldap_cur_pass_array{
  332.                     array_push($msgs,_("Unable to find user's password attribute."));
  333.                     return $msgs;
  334.                 }
  335.  
  336.                 // compare passwords
  337.                 if (cpw_ldap_compare_pass($cpw_ldap_cur_pass_array[0],$curpw,$msgs)) {
  338.                     @ldap_unbind($cpw_ldap_con);
  339.                     // errors are added to $msgs by cpw_ldap_compare_pass()
  340.                     return $msgs;
  341.                 }
  342.             }
  343.         else {
  344.             $cpw_ldap_binding=@ldap_bind($cpw_ldap_con,$cpw_ldap_userdn,$curpw);
  345.         }
  346.  
  347.         if ($cpw_ldap_binding{
  348.             array_push($msgs,
  349.                        _("Unable to rebind to LDAP server."),
  350.                        sprintf(_("Server replied: %s"),ldap_error($cpw_ldap_con)));
  351.             @ldap_unbind($cpw_ldap_con);
  352.             return $msgs;
  353.         }
  354.  
  355.         // repeat search in order to get password info
  356.         if (isset($cpw_ldap_res2))
  357.             $cpw_ldap_search_err=cpw_ldap_uid_search($cpw_ldap_con,$cpw_ldap_basedn,$msgs,$cpw_ldap_res2,$cpw_ldap_userdn);
  358.  
  359.         // check for connection errors and stop execution if something is wrong
  360.         if ($cpw_ldap_search_err{
  361.             @ldap_unbind($cpw_ldap_con);
  362.             return $msgs;
  363.         }
  364.  
  365.         // getpassword. suppress errors and check value returned by function call
  366.         $cpw_ldap_cur_pass_array=@ldap_get_values($cpw_ldap_con,ldap_first_entry($cpw_ldap_con,$cpw_ldap_res2),'userpassword');
  367.  
  368.         // check if ldap_get_values() have found userpassword field.
  369.         // Error differs from previous one, because user managed to authenticate.
  370.         if ($cpw_ldap_cur_pass_array{
  371.             array_push($msgs,_("LDAP server uses different attribute to store user's password."));
  372.             return $msgs;
  373.         }
  374.  
  375.         // encrypt new password (old password is needed for plaintext encryption detection)
  376.         $cpw_ldap_new_pass=cpw_ldap_encrypt_pass($newpw,$cpw_ldap_cur_pass_array[0],$msgs,$curpw);
  377.  
  378.         if ($cpw_ldap_new_pass{
  379.             @ldap_unbind($cpw_ldap_con);
  380.             return $msgs;
  381.         }
  382.  
  383.         // set new password. suppress ldap_modify errors. script checks and displays ldap_modify errors.
  384.         $ldap_pass_change=@ldap_modify($cpw_ldap_con,$cpw_ldap_userdn,array('userpassword'=>$cpw_ldap_new_pass));
  385.  
  386.         // check if ldap_modify was successful
  387.         if($ldap_pass_change{
  388.             array_push($msgs,ldap_error($cpw_ldap_con));
  389.         }
  390.  
  391.         // close connection
  392.         @ldap_unbind($cpw_ldap_con);
  393.     else {
  394.         array_push($msgs,_("Unable to connect to LDAP server."));
  395.     }
  396.     return $msgs;
  397. }
  398.  
  399. /** backend support functions **/
  400.  
  401. /**
  402.  * Sanitizes LDAP query strings.
  403.  * original code - ldapquery plugin.
  404.  * See rfc2254
  405.  * @link http://www.faqs.org/rfcs/rfc2254.html
  406.  * @param string $string 
  407.  * @return string sanitized string
  408.  */
  409. function cpw_ldap_specialchars($string{
  410.     $sanitized=array('\\' => '\5c',
  411.                      '*' => '\2a',
  412.                      '(' => '\28',
  413.                      ')' => '\29',
  414.                      "\x00" => '\00');
  415.  
  416.     return str_replace(array_keys($sanitized),array_values($sanitized),$string);
  417. }
  418.  
  419. /**
  420.  * returns crypto algorithm used in password.
  421.  * @param string $pass encrypted/hashed password
  422.  * @return string lowercased crypto algorithm name
  423.  */
  424. function cpw_ldap_get_crypto($pass,$curpass=''{
  425.     $ret false;
  426.  
  427.     if (preg_match("/^\{(.+)\}+/",$pass,$crypto)) {
  428.         $ret=strtolower($crypto[1]);
  429.     }
  430.  
  431.     if ($ret=='crypt'{
  432.         // {CRYPT} can be standard des crypt, extended des crypt, md5 crypt or blowfish
  433.         // depends on first salt symbols (ext_des = '_', md5 = '$1$', blowfish = '$2')
  434.         // and length of salt (des = 2 chars, ext_des = 9, md5 = 12, blowfish = 16).
  435.         if (preg_match("/^\{crypt\}\\\$1\\\$+/i",$pass)) {
  436.             $ret='md5crypt';
  437.         elseif (preg_match("/^\{crypt\}\\\$2+/i",$pass)) {
  438.             $ret='blowfish';
  439.         elseif (preg_match("/^\{crypt\}_+/i",$pass)) {
  440.             $ret='extcrypt';
  441.         }
  442.     }
  443.  
  444.     // maybe password is plaintext
  445.     if ($ret && $curpass!='' && $pass==$curpass$ret='plaintext';
  446.  
  447.     return $ret;
  448. }
  449.  
  450. /**
  451.  * Search LDAP for user id.
  452.  * @param object $ldap_con ldap connection
  453.  * @param string $ldap_basedn ldap basedn
  454.  * @param array $msgs error messages
  455.  * @param object $results ldap search results
  456.  * @param string $userdn DN of found entry
  457.  * @param boolean $onlyone require unique search results
  458.  * @return boolean false if connection failed.
  459.  */
  460. function cpw_ldap_uid_search($ldap_con,$ldap_basedn,&$msgs,&$results,&$userdn,$onlyone=true{
  461.     global $cpw_ldap_userid_attr,$username;
  462.  
  463.     $ret=true;
  464.  
  465.     $results=ldap_search($ldap_con,$ldap_basedn,cpw_ldap_specialchars($cpw_ldap_userid_attr '=' $username));
  466.  
  467.     if ($results{
  468.         array_push($msgs,
  469.                    _("Unable to find user's DN."),
  470.                    _("Search error."),
  471.                    sprintf(_("Error: %s"),ldap_error($ldap_con)));
  472.         $ret=false;
  473.     elseif ($onlyone && ldap_count_entries($ldap_con,$results)>1{
  474.         array_push($msgs,_("Multiple userid matches found."));
  475.         $ret=false;
  476.     elseif ($userdn ldap_get_dn($ldap_con,ldap_first_entry($ldap_con,$results))) {
  477.         // ldap_get_dn() returned error
  478.         array_push($msgs,
  479.                    _("Unable to find user's DN."),
  480.                    _("ldap_get_dn error."));
  481.         $ret=false;
  482.     }
  483.     return $ret;
  484. }
  485.  
  486. /**
  487.  * Encrypts LDAP password
  488.  *
  489.  * if $cpw_ldap_default_crypto is set to empty string or $same_crypto is set,
  490.  * uses same crypto as in old password.
  491.  * See phpldapadmin password_hash() function
  492.  * @link http://phpldapadmin.sf.net
  493.  * @param string $pass string that has to be encrypted/hashed
  494.  * @param string $cur_pass_hash old password hash
  495.  * @param array $msgs error message
  496.  * @param string $curpass current password. Used for plaintext password detection.
  497.  * @return string encrypted/hashed password or false
  498.  */
  499. function cpw_ldap_encrypt_pass($pass,$cur_pass_hash,&$msgs,$curpass=''{
  500.     global $cpw_ldap_default_crypto;
  501.  
  502.     // which crypto should be used to encode/hash password
  503.     if ($cpw_ldap_default_crypto==''{
  504.         $ldap_crypto=cpw_ldap_get_crypto($cur_pass_hash,$curpass);
  505.     else {
  506.         $ldap_crypto=$cpw_ldap_default_crypto;
  507.     }
  508.     return cpw_ldap_password_hash($pass,$ldap_crypto,$msgs);
  509. }
  510.  
  511. /**
  512.  * create hashed password
  513.  * @param string $pass plain text password
  514.  * @param string $crypto used crypto algorithm
  515.  * @param array $msgs array used for error messages
  516.  * @param string $forced_salt salt that should be used during hashing.
  517.  *  Is used only when is not set to empty string. Salt should be formated
  518.  *  according to $crypto requirements.
  519.  * @return hashed password or false.
  520.  */
  521. function cpw_ldap_password_hash($pass,$crypto,&$msgs,$forced_salt=''{
  522.     // set default return code
  523.     $ret=false;
  524.  
  525.     // lowercase crypto just in case
  526.     $crypto=strtolower($crypto);
  527.  
  528.     // extra symbols used for random string in crypt salt
  529.     // squirrelmail GenerateRandomString() adds alphanumerics with third argument = 7.
  530.     $extra_salt_chars='./';
  531.  
  532.     // encrypt/hash password
  533.     switch ($crypto{
  534.     case 'md4':
  535.         // minimal requirement = php with mhash extension
  536.         if function_exists'mhash' && defined('MHASH_MD4')) {
  537.             $ret '{MD4}' base64_encodemhashMHASH_MD4$pass) );
  538.         else {
  539.             array_push($msgs,
  540.                        sprintf(_("Unsupported crypto: %s"),'md4'),
  541.                        _("PHP mhash extension is missing or does not support selected crypto."));
  542.         }
  543.         break;
  544.     case 'md5':
  545.         $ret='{MD5}' base64_encode(pack('H*',md5($pass)));
  546.         break;
  547.     case 'smd5':
  548.         // minimal requirement = mhash extension with md5 support and php 4.0.4.
  549.         iffunction_exists'mhash' && function_exists'mhash_keygen_s2k' && defined('MHASH_MD5')) {
  550.             if ($forced_salt!=''{
  551.                 $salt=$forced_salt;
  552.             else {
  553.                 $salt mhash_keygen_s2kMHASH_MD5$passsubstrpack"h*"md5mt_rand() ) )0));
  554.             }
  555.             $ret "{SMD5}".base64_encodemhashMHASH_MD5$pass.$salt ).$salt );
  556.         else {
  557.             // use two array_push calls in order to display messages in different lines.
  558.             array_push($msgs,
  559.                        sprintf(_("Unsupported crypto: %s"),'smd5'),
  560.                        _("PHP mhash extension is missing or does not support selected crypto."));
  561.         }
  562.         break;
  563.     case 'rmd160':
  564.         // minimal requirement = php with mhash extension
  565.         if function_exists'mhash' && defined('MHASH_RIPEMD160')) {
  566.             $ret '{RMD160}' base64_encodemhashMHASH_RIPEMD160$pass) );
  567.         else {
  568.             array_push($msgs,
  569.                        sprintf(_("Unsupported crypto: %s"),'ripe-md160'),
  570.                        _("PHP mhash extension is missing or does not support selected crypto."));
  571.         }
  572.         break;
  573.     case 'sha':
  574.         // minimal requirement = php 4.3.0+ or php with mhash extension
  575.         if function_exists('sha1'&& defined('MHASH_SHA1')) {
  576.             // use php 4.3.0+ sha1 function, if it is available.
  577.             $ret '{SHA}' base64_encode(pack('H*',sha1($pass)));
  578.         elseiffunction_exists'mhash' ) ) {
  579.             $ret '{SHA}' base64_encodemhashMHASH_SHA1$pass) );
  580.         else {
  581.             array_push($msgs,
  582.                        sprintf(_("Unsupported crypto: %s"),'sha'),
  583.                        _("PHP mhash extension is missing or does not support selected crypto."));
  584.         }
  585.         break;
  586.     case 'ssha':
  587.         // minimal requirement = mhash extension and php 4.0.4
  588.         iffunction_exists'mhash' && function_exists'mhash_keygen_s2k' && defined('MHASH_SHA1')) {
  589.             if ($forced_salt!=''{
  590.                 $salt=$forced_salt;
  591.             else {
  592.                 $salt mhash_keygen_s2kMHASH_SHA1$passsubstrpack"h*"md5mt_rand() ) )0));
  593.             }
  594.             $ret "{SSHA}".base64_encodemhashMHASH_SHA1$pass.$salt ).$salt );
  595.         else {
  596.             array_push($msgs,
  597.                        sprintf(_("Unsupported crypto: %s"),'ssha'),
  598.                        _("PHP mhash extension is missing or does not support selected crypto."));
  599.         }
  600.         break;
  601.     case 'crypt':
  602.         if (defined('CRYPT_STD_DES'&& CRYPT_STD_DES==1{
  603.             $ret '{CRYPT}' crypt($pass,GenerateRandomString(2,$extra_salt_chars,7));
  604.         else {
  605.             array_push($msgs,
  606.                        sprintf(_("Unsupported crypto: %s"),'crypt'),
  607.                        _("System crypt library doesn't support standard DES crypt."));
  608.         }
  609.         break;
  610.     case 'md5crypt':
  611.         // check if crypt() supports md5
  612.         if (defined('CRYPT_MD5'&& CRYPT_MD5==1{
  613.             $ret '{CRYPT}' crypt($pass,'$1$' GenerateRandomString(9,$extra_salt_chars,7));
  614.         else {
  615.             array_push($msgs,
  616.                        sprintf(_("Unsupported crypto: %s"),'md5crypt'),
  617.                        _("System crypt library doesn't have MD5 support."));
  618.         }
  619.         break;
  620.     case 'extcrypt':
  621.         // check if crypt() supports extended des
  622.         if (defined('CRYPT_EXT_DES'&& CRYPT_EXT_DES==1{
  623.             $ret '{CRYPT}' crypt($pass,'_' GenerateRandomString(8,$extra_salt_chars,7));
  624.         else {
  625.             array_push($msgs,
  626.                        sprintf(_("Unsupported crypto: %s"),'ext_des'),
  627.                        _("System crypt library doesn't support extended DES crypt."));
  628.         }
  629.         break;
  630.     case 'blowfish':
  631.         // check if crypt() supports blowfish
  632.         if (defined('CRYPT_BLOWFISH'&& CRYPT_BLOWFISH==1{
  633.             $ret '{CRYPT}' crypt($pass,'$2a$12$' GenerateRandomString(13,$extra_salt_chars,7));
  634.         else {
  635.             array_push($msgs,
  636.                        sprintf(_("Unsupported crypto: %s"),'Blowfish'),
  637.                        _("System crypt library doesn't have Blowfish support."));
  638.         }
  639.         break;
  640.     case 'plaintext':
  641.         // clear plain text password
  642.         $ret=$pass;
  643.         break;
  644.     default:
  645.         array_push($msgs,sprintf(_("Unsupported crypto: %s"),
  646.                                  (is_string($ldap_cryptosm_encode_html_special_chars($ldap_crypto_("unknown"))));
  647.     }
  648.     return $ret;
  649. }
  650.  
  651. /**
  652.  * compares two passwords
  653.  * Code reuse. See phpldapadmin password_compare() function.
  654.  * Some parts of code was rewritten to backend specifics.
  655.  * @link http://phpldapadmin.sf.net
  656.  * @param string $pass_hash hashed password string with password type indicators
  657.  * @param string $pass_clear plain text password
  658.  * @param array $msgs error messages
  659.  * @return boolean true, if passwords match
  660.  */
  661. function cpw_ldap_compare_pass($pass_hash,$pass_clear,&$msgs{
  662.     $ret=false;
  663.  
  664.     ifpreg_match"/{([^}]+)}(.*)/"$pass_hash$cypher ) ) {
  665.         $pass_hash $cypher[2];
  666.         $_cypher strtolower($cypher[1]);
  667.     else  {
  668.         $_cypher NULL;
  669.     }
  670.  
  671.     switch$_cypher {
  672.     case 'ssha':
  673.         // Salted SHA
  674.         // check for mhash support
  675.         if function_exists('mhash'&& defined('MHASH_SHA1')) {
  676.             $hash base64_decode($pass_hash);
  677.             $salt substr($hash-4);
  678.             $new_hash base64_encodemhashMHASH_SHA1$pass_clear.$salt).$salt );
  679.             ifstrcmp$pass_hash$new_hash == )
  680.                 $ret=true;
  681.         else {
  682.             array_push($msgs,
  683.                        _("Unable to validate user's password."),
  684.                        _("PHP mhash extension is missing or does not support selected crypto."));
  685.         }
  686.         break;
  687.     case 'smd5':
  688.         // Salted MD5
  689.         // check for mhash support
  690.         if function_exists('mhash'&& defined('MHASH_MD5')) {
  691.             $hash base64_decode($pass_hash);
  692.             $salt substr($hash-4);
  693.             $new_hash base64_encodemhashMHASH_MD5$pass_clear.$salt).$salt );
  694.             ifstrcmp$pass_hash$new_hash == 0)
  695.                 $ret=true;
  696.         else {
  697.             array_push($msgs,
  698.                        _("Unable to validate user's password."),
  699.                        _("PHP mhash extension is missing or does not support selected crypto."));
  700.         }
  701.         break;
  702.     case 'sha':
  703.         // SHA crypted passwords
  704.         ifstrcasecmpcpw_ldap_password_hash($pass_clear,'sha',$msgs)"{SHA}".$pass_hash == 0)
  705.             $ret=true;
  706.         break;
  707.     case 'rmd160':
  708.         // RIPE-MD160 crypted passwords
  709.         ifstrcasecmpcpw_ldap_password_hash($pass_clear,'rmd160',$msgs)"{RMD160}".$pass_hash == )
  710.             $ret=true;
  711.         break;
  712.     case 'md5':
  713.         // MD5 crypted passwords
  714.         ifstrcasecmpcpw_ldap_password_hash($pass_clear,'md5',$msgs)"{MD5}".$pass_hash == )
  715.             $ret=true;
  716.         break;
  717.     case 'md4':
  718.         // MD4 crypted passwords
  719.         ifstrcasecmpcpw_ldap_password_hash($pass_clear,'md4',$msgs)"{MD4}".$pass_hash == )
  720.             $ret=true;
  721.         break;
  722.     case 'crypt':
  723.         // Crypt passwords
  724.         if(  preg_match"/^\\\$2+/",$pass_hash ) ) // Check if it's blowfish crypt
  725.             // check CRYPT_BLOWFISH here.
  726.             // ldap server might support it, but php can be on other OS
  727.             if (defined('CRYPT_BLOWFISH'&& CRYPT_BLOWFISH==1{
  728.                 ifcrypt$pass_clear$pass_hash == $pass_hash )
  729.                     $ret=true;
  730.             else {
  731.                 array_push($msgs,
  732.                            _("Unable to validate user's password."),
  733.                            _("Blowfish is not supported by webserver's system crypt library."));
  734.             }
  735.         elseifstrstr$pass_hash'$1$' ) ) // Check if it's md5 crypt
  736.             // check CRYPT_MD5 here.
  737.             // ldap server might support it, but php might be on other OS
  738.             if (defined('CRYPT_MD5'&& CRYPT_MD5==1{
  739.                 list(,$type,$salt,$hashexplode('$',$pass_hash);
  740.                 ifcrypt$pass_clear'$1$' .$salt == $pass_hash )
  741.                     $ret=true;
  742.             else {
  743.                 array_push($msgs,
  744.                            _("Unable to validate user's password."),
  745.                            _("MD5 is not supported by webserver's system crypt library."));
  746.             }
  747.         elseifstrstr$pass_hash'_' ) ) // Check if it's extended des crypt
  748.             // check CRYPT_EXT_DES here.
  749.             // ldap server might support it, but php might be on other OS
  750.             if (defined('CRYPT_EXT_DES'&& CRYPT_EXT_DES==1{
  751.                 ifcrypt$pass_clear$pass_hash == $pass_hash )
  752.                     $ret=true;
  753.             else {
  754.                 array_push($msgs,
  755.                            _("Unable to validate user's password."),
  756.                            _("Extended DES crypt is not supported by webserver's system crypt library."));
  757.             }
  758.         else {
  759.             // it is possible that this test is useless and any crypt library supports it, but ...
  760.             if (defined('CRYPT_STD_DES'&& CRYPT_STD_DES==1{
  761.                 // plain crypt password
  762.                 ifcrypt($pass_clear$pass_hash == $pass_hash )
  763.                     $ret=true;
  764.             else {
  765.                 array_push($msgs,
  766.                            _("Unable to validate user's password."),
  767.                            _("Standard DES crypt is not supported by webserver's system crypt library."));
  768.             }
  769.         }
  770.         break;
  771.     // No crypt is given, assume plaintext passwords are used
  772.     default:
  773.         if$pass_clear == $pass_hash )
  774.             $ret=true;
  775.         break;
  776.     }
  777.     if ($ret && empty($msgs)) {
  778.         array_push($msgs,CPW_CURRENT_NOMATCH);
  779.     }
  780.     return $ret;
  781. }

Documentation generated on Mon, 13 Jan 2020 04:22:57 +0100 by phpDocumentor 1.4.3