function save($curpass, $passwd)
 {
     $rcmail = rcmail::get_instance();
     $this->debug = $rcmail->config->get('ldap_debug');
     $ldap_host = $rcmail->config->get('password_ldap_host');
     $ldap_port = $rcmail->config->get('password_ldap_port');
     $this->_debug("C: Connect to {$ldap_host}:{$ldap_port}");
     // Connect
     if (!($ds = ldap_connect($ldap_host, $ldap_port))) {
         $this->_debug("S: NOT OK");
         rcube::raise_error(array('code' => 100, 'type' => 'ldap', 'file' => __FILE__, 'line' => __LINE__, 'message' => "Could not connect to LDAP server"), true);
         return PASSWORD_CONNECT_ERROR;
     }
     $this->_debug("S: OK");
     // Set protocol version
     ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, $rcmail->config->get('password_ldap_version'));
     // Start TLS
     if ($rcmail->config->get('password_ldap_starttls')) {
         if (!ldap_start_tls($ds)) {
             ldap_unbind($ds);
             return PASSWORD_CONNECT_ERROR;
         }
     }
     // include 'ldap' driver, we share some static methods with it
     require_once INSTALL_PATH . 'plugins/password/drivers/ldap.php';
     // other plugins might want to modify user DN
     $plugin = $rcmail->plugins->exec_hook('password_ldap_bind', array('user_dn' => '', 'conn' => $ds));
     // Build user DN
     if (!empty($plugin['user_dn'])) {
         $user_dn = $plugin['user_dn'];
     } else {
         if ($user_dn = $rcmail->config->get('password_ldap_userDN_mask')) {
             $user_dn = rcube_ldap_password::substitute_vars($user_dn);
         } else {
             $user_dn = $this->search_userdn($rcmail, $ds);
         }
     }
     if (empty($user_dn)) {
         ldap_unbind($ds);
         return PASSWORD_CONNECT_ERROR;
     }
     // Connection method
     switch ($rcmail->config->get('password_ldap_method')) {
         case 'admin':
             $binddn = $rcmail->config->get('password_ldap_adminDN');
             $bindpw = $rcmail->config->get('password_ldap_adminPW');
             break;
         case 'user':
         default:
             $binddn = $user_dn;
             $bindpw = $curpass;
             break;
     }
     $lchattr = $rcmail->config->get('password_ldap_lchattr');
     $pwattr = $rcmail->config->get('password_ldap_pwattr');
     $smbpwattr = $rcmail->config->get('password_ldap_samba_pwattr');
     $smblchattr = $rcmail->config->get('password_ldap_samba_lchattr');
     $samba = $rcmail->config->get('password_ldap_samba');
     $pass_mode = $rcmail->config->get('password_ldap_encodage');
     $crypted_pass = password::hash_password($passwd, $pass_mode);
     // Support password_ldap_samba option for backward compat.
     if ($samba && !$smbpwattr) {
         $smbpwattr = 'sambaNTPassword';
         $smblchattr = 'sambaPwdLastSet';
     }
     // Crypt new password
     if (!$crypted_pass) {
         return PASSWORD_CRYPT_ERROR;
     }
     // Crypt new Samba password
     if ($smbpwattr && !($samba_pass = password::hash_password($passwd, 'samba'))) {
         return PASSWORD_CRYPT_ERROR;
     }
     $this->_debug("C: Bind {$binddn}, pass: **** [" . strlen($bindpw) . "]");
     // Bind
     if (!ldap_bind($ds, $binddn, $bindpw)) {
         $this->_debug("S: " . ldap_error($ds));
         ldap_unbind($ds);
         return PASSWORD_CONNECT_ERROR;
     }
     $this->_debug("S: OK");
     $entry[$pwattr] = $crypted_pass;
     // Update PasswordLastChange Attribute if desired
     if ($lchattr) {
         $entry[$lchattr] = (int) (time() / 86400);
     }
     // Update Samba password
     if ($smbpwattr) {
         $entry[$smbpwattr] = $samba_pass;
     }
     // Update Samba password last change
     if ($smblchattr) {
         $entry[$smblchattr] = time();
     }
     $this->_debug("C: Modify {$user_dn}: " . print_r($entry, true));
     if (!ldap_modify($ds, $user_dn, $entry)) {
         $this->_debug("S: " . ldap_error($ds));
         ldap_unbind($ds);
         return PASSWORD_CONNECT_ERROR;
     }
     $this->_debug("S: OK");
     // All done, no error
     ldap_unbind($ds);
     return PASSWORD_SUCCESS;
 }
Example #2
0
 public function save($curpass, $passwd)
 {
     $rcmail = rcmail::get_instance();
     require_once 'Net/LDAP2.php';
     // Building user DN
     if ($userDN = $rcmail->config->get('password_ldap_userDN_mask')) {
         $userDN = self::substitute_vars($userDN);
     } else {
         $userDN = $this->search_userdn($rcmail);
     }
     if (empty($userDN)) {
         return PASSWORD_CONNECT_ERROR;
     }
     // Connection Method
     switch ($rcmail->config->get('password_ldap_method')) {
         case 'admin':
             $binddn = $rcmail->config->get('password_ldap_adminDN');
             $bindpw = $rcmail->config->get('password_ldap_adminPW');
             break;
         case 'user':
         default:
             $binddn = $userDN;
             $bindpw = $curpass;
             break;
     }
     // Configuration array
     $ldapConfig = array('binddn' => $binddn, 'bindpw' => $bindpw, 'basedn' => $rcmail->config->get('password_ldap_basedn'), 'host' => $rcmail->config->get('password_ldap_host'), 'port' => $rcmail->config->get('password_ldap_port'), 'starttls' => $rcmail->config->get('password_ldap_starttls'), 'version' => $rcmail->config->get('password_ldap_version'));
     // Connecting using the configuration array
     $ldap = Net_LDAP2::connect($ldapConfig);
     // Checking for connection error
     if (is_a($ldap, 'PEAR_Error')) {
         return PASSWORD_CONNECT_ERROR;
     }
     $force = $rcmail->config->get('password_ldap_force_replace');
     $pwattr = $rcmail->config->get('password_ldap_pwattr');
     $lchattr = $rcmail->config->get('password_ldap_lchattr');
     $smbpwattr = $rcmail->config->get('password_ldap_samba_pwattr');
     $smblchattr = $rcmail->config->get('password_ldap_samba_lchattr');
     $samba = $rcmail->config->get('password_ldap_samba');
     $encodage = $rcmail->config->get('password_ldap_encodage');
     // Support multiple userPassword values where desired.
     // multiple encodings can be specified separated by '+' (e.g. "cram-md5+ssha")
     $encodages = explode('+', $encodage);
     $crypted_pass = array();
     foreach ($encodages as $enc) {
         if ($cpw = password::hash_password($passwd, $enc)) {
             $crypted_pass[] = $cpw;
         }
     }
     // Support password_ldap_samba option for backward compat.
     if ($samba && !$smbpwattr) {
         $smbpwattr = 'sambaNTPassword';
         $smblchattr = 'sambaPwdLastSet';
     }
     // Crypt new password
     if (empty($crypted_pass)) {
         return PASSWORD_CRYPT_ERROR;
     }
     // Crypt new samba password
     if ($smbpwattr && !($samba_pass = password::hash_password($passwd, 'samba'))) {
         return PASSWORD_CRYPT_ERROR;
     }
     // Writing new crypted password to LDAP
     $userEntry = $ldap->getEntry($userDN);
     if (Net_LDAP2::isError($userEntry)) {
         return PASSWORD_CONNECT_ERROR;
     }
     if (!$userEntry->replace(array($pwattr => $crypted_pass), $force)) {
         return PASSWORD_CONNECT_ERROR;
     }
     // Updating PasswordLastChange Attribute if desired
     if ($lchattr) {
         $current_day = (int) (time() / 86400);
         if (!$userEntry->replace(array($lchattr => $current_day), $force)) {
             return PASSWORD_CONNECT_ERROR;
         }
     }
     // Update Samba password and last change fields
     if ($smbpwattr) {
         $userEntry->replace(array($smbpwattr => $samba_pass), $force);
     }
     // Update Samba password last change field
     if ($smblchattr) {
         $userEntry->replace(array($smblchattr => time()), $force);
     }
     if (Net_LDAP2::isError($userEntry->update())) {
         return PASSWORD_CONNECT_ERROR;
     }
     // All done, no error
     return PASSWORD_SUCCESS;
 }
Example #3
0
 function save($curpass, $passwd)
 {
     $rcmail = rcmail::get_instance();
     if (!($sql = $rcmail->config->get('password_query'))) {
         $sql = 'SELECT update_passwd(%c, %u)';
     }
     if ($dsn = $rcmail->config->get('password_db_dsn')) {
         $db = rcube_db::factory($dsn, '', false);
         $db->set_debug((bool) $rcmail->config->get('sql_debug'));
     } else {
         $db = $rcmail->get_dbh();
     }
     if ($db->is_error()) {
         return PASSWORD_ERROR;
     }
     // new password - default hash method
     if (strpos($sql, '%P') !== false) {
         $password = password::hash_password($passwd);
         if ($password === false) {
             return PASSWORD_CRYPT_ERROR;
         }
         $sql = str_replace('%P', $db->quote($password), $sql);
     }
     // old password - default hash method
     if (strpos($sql, '%O') !== false) {
         $password = password::hash_password($curpass);
         if ($password === false) {
             return PASSWORD_CRYPT_ERROR;
         }
         $sql = str_replace('%O', $db->quote($password), $sql);
     }
     // crypted password (deprecated, use %P)
     if (strpos($sql, '%c') !== false) {
         $password = password::hash_password($passwd, 'crypt', false);
         if ($password === false) {
             return PASSWORD_CRYPT_ERROR;
         }
         $sql = str_replace('%c', $db->quote($password), $sql);
     }
     // dovecotpw (deprecated, use %P)
     if (strpos($sql, '%D') !== false) {
         $password = password::hash_password($passwd, 'dovecot', false);
         if ($password === false) {
             return PASSWORD_CRYPT_ERROR;
         }
         $sql = str_replace('%D', $db->quote($password), $sql);
     }
     // hashed passwords (deprecated, use %P)
     if (strpos($sql, '%n') !== false) {
         $password = password::hash_password($passwd, 'hash', false);
         if ($password === false) {
             return PASSWORD_CRYPT_ERROR;
         }
         $sql = str_replace('%n', $db->quote($password, 'text'), $sql);
     }
     // hashed passwords (deprecated, use %P)
     if (strpos($sql, '%q') !== false) {
         $password = password::hash_password($curpass, 'hash', false);
         if ($password === false) {
             return PASSWORD_CRYPT_ERROR;
         }
         $sql = str_replace('%q', $db->quote($password, 'text'), $sql);
     }
     // Handle clear text passwords securely (#1487034)
     $sql_vars = array();
     if (preg_match_all('/%[p|o]/', $sql, $m)) {
         foreach ($m[0] as $var) {
             if ($var == '%p') {
                 $sql = preg_replace('/%p/', '?', $sql, 1);
                 $sql_vars[] = (string) $passwd;
             } else {
                 // %o
                 $sql = preg_replace('/%o/', '?', $sql, 1);
                 $sql_vars[] = (string) $curpass;
             }
         }
     }
     $local_part = $rcmail->user->get_username('local');
     $domain_part = $rcmail->user->get_username('domain');
     $username = $_SESSION['username'];
     $host = $_SESSION['imap_host'];
     // convert domains to/from punnycode
     if ($rcmail->config->get('password_idn_ascii')) {
         $domain_part = rcube_utils::idn_to_ascii($domain_part);
         $username = rcube_utils::idn_to_ascii($username);
         $host = rcube_utils::idn_to_ascii($host);
     } else {
         $domain_part = rcube_utils::idn_to_utf8($domain_part);
         $username = rcube_utils::idn_to_utf8($username);
         $host = rcube_utils::idn_to_utf8($host);
     }
     // at least we should always have the local part
     $sql = str_replace('%l', $db->quote($local_part, 'text'), $sql);
     $sql = str_replace('%d', $db->quote($domain_part, 'text'), $sql);
     $sql = str_replace('%u', $db->quote($username, 'text'), $sql);
     $sql = str_replace('%h', $db->quote($host, 'text'), $sql);
     $res = $db->query($sql, $sql_vars);
     if (!$db->is_error()) {
         if (strtolower(substr(trim($sql), 0, 6)) == 'select') {
             if ($db->fetch_array($res)) {
                 return PASSWORD_SUCCESS;
             }
         } else {
             // This is the good case: 1 row updated
             if ($db->affected_rows($res) == 1) {
                 return PASSWORD_SUCCESS;
             }
             // @TODO: Some queries don't affect any rows
             // Should we assume a success if there was no error?
         }
     }
     return PASSWORD_ERROR;
 }