From d432ef7f84c414a158b09fa8886cdaf5f848070d Mon Sep 17 00:00:00 2001 From: Ralf Becker Date: Fri, 13 Jul 2018 09:57:22 +0200 Subject: [PATCH] * Univention: fix not working password change (setting Kerberos credentials) --- api/src/Accounts/Univention.php | 88 +++++++++++++++++++++++++++++++++ api/src/Auth/Univention.php | 43 ++++++++++++++++ setup/account_migration.php | 1 - 3 files changed, 131 insertions(+), 1 deletion(-) create mode 100644 api/src/Auth/Univention.php diff --git a/api/src/Accounts/Univention.php b/api/src/Accounts/Univention.php index 72e9e5363c..d349f5edcf 100644 --- a/api/src/Accounts/Univention.php +++ b/api/src/Accounts/Univention.php @@ -255,4 +255,92 @@ class Univention extends Ldap //return true; return file_exists(self::DIRECTORY_MANAGER_BIN) && is_executable(self::DIRECTORY_MANAGER_BIN); } + + /** + * changes password in LDAP + * + * If $old_passwd is given, the password change is done binded as user and NOT with the + * "root" dn given in the configurations. + * + * @param string $old_passwd must be cleartext or empty to not to be checked + * @param string $new_passwd must be cleartext + * @param int $account_id account id of user whose passwd should be changed + * @param boolean $update_lastchange =true + * @return boolean true if password successful changed, false otherwise + */ + function change_password($old_passwd, $new_passwd, $account_id=0, $update_lastchange=true) + { + if (!self::available()) + { + return false; + } + if (!$account_id) + { + $username = $GLOBALS['egw_info']['user']['account_lid']; + } + else + { + $username = Api\Translation::convert($GLOBALS['egw']->accounts->id2name($account_id), + Api\Translation::charset(),'utf-8'); + } + if ($this->debug) error_log(__METHOD__."('$old_passwd','$new_passwd',$account_id, $update_lastchange) username='$username'"); + + $filter = str_replace(array('%user','%domain'),array($username,$GLOBALS['egw_info']['user']['domain']), + $GLOBALS['egw_info']['server']['ldap_search_filter'] ? $GLOBALS['egw_info']['server']['ldap_search_filter'] : '(uid=%user)'); + + $ds = $ds_admin = Api\Ldap::factory(); + $sri = ldap_search($ds, $GLOBALS['egw_info']['server']['ldap_context'], $filter); + $allValues = ldap_get_entries($ds, $sri); + + if ($update_lastchange) + { + // ToDo: $entry['shadowlastchange'] = round((time()-date('Z')) / (24*3600)); + } + + $dn = $allValues[0]['dn']; + + if($old_passwd) // if old password given (not called by admin) --> bind as that user to change the pw + { + try { + $ds = Api\Ldap::factory(true, '', $dn, $old_passwd); + } + catch (Api\Exception\NoPermission $e) { + unset($e); + return false; // wrong old user password + } + } + $ssh = null;//'/usr/bin/ssh -o "UserKnownHostsFile=/dev/null" -o "StrictHostKeyChecking=no" -i /var/lib/egroupware/id_rsa root@10.44.22.194'; + $config = $this->frontend->config && $this->frontend->config['ldap_context'] ? + $this->frontend->config : $GLOBALS['egw_info']['server']; + + $params = array( + 'users/user','modify', + '--binddn', $config['ldap_root_dn'], + '--bindpwd', 5=>$config['ldap_root_pw'], + '--dn', $dn, + '--set', 'password='.$new_passwd, + ); + if ($old_passwd) + { + $params[] = '--set'; + $params[] = 'pwdChangeNextLogin=0'; + } + $cmd = self::DIRECTORY_MANAGER_BIN.' '.implode(' ', array_map('escapeshellarg', $params)); + if (isset($ssh)) $cmd = $ssh.' bash -c "\\"'.$cmd.'\\""'; + $output_arr = $ret = $matches = null; + exec($cmd, $output_arr, $ret); + $output = implode("\n", $output_arr); + if ($ret || !preg_match('/^Object modified: ((uid|cn)=.*)$/mui', $output, $matches)) + { + $params[5] = '********'; // mask out password! + $cmd = self::DIRECTORY_MANAGER_BIN.' '.implode(' ', array_map('escapeshellarg', $params)); + throw new Api\Exception\WrongUserinput($cmd."\nreturned\n".$output); + } + if($old_passwd) // if old password given (not called by admin) update the password in the session + { + // using time() is sufficient to represent the current time, we do not need the timestamp written to the storage + Api\Cache::setSession('phpgwapi','auth_alpwchange_val',time()); + } + return $new_passwd; + } } diff --git a/api/src/Auth/Univention.php b/api/src/Auth/Univention.php new file mode 100644 index 0000000000..a8ad30b688 --- /dev/null +++ b/api/src/Auth/Univention.php @@ -0,0 +1,43 @@ + + * + * @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License + * @package api + * @subpackage auth + */ + +namespace EGroupware\Api\Auth; + +use EGroupware\Api; + +/** + * Univention LDAP Backend for auth + * + * This backend is mostly identical to LDAP backend and need to be configured in the same way. + * + * Only difference is that passwords are changed via univention-directory-manager CLI program, + * to generate necesary hashes and Kerberos stuff. + */ +class Univention extends Ldap +{ + /** + * changes password in LDAP + * + * If $old_passwd is given, the password change is done binded as user and NOT with the + * "root" dn given in the configurations. + * + * @param string $old_passwd must be cleartext or empty to not to be checked + * @param string $new_passwd must be cleartext + * @param int $account_id account id of user whose passwd should be changed + * @param boolean $update_lastchange =true + * @return boolean true if password successful changed, false otherwise + */ + function change_password($old_passwd, $new_passwd, $account_id=0, $update_lastchange=true) + { + return Api\Accounts::getInstance()->backend->change_password($old_passwd, $new_passwd, $account_id, $update_lastchange); + } +} \ No newline at end of file diff --git a/setup/account_migration.php b/setup/account_migration.php index 2ec39f6c17..ce663288bf 100644 --- a/setup/account_migration.php +++ b/setup/account_migration.php @@ -167,7 +167,6 @@ else // do the migration if ($_POST['migrate']) { Api\Config::save_value('account_repository', $GLOBALS['egw_info']['server']['account_repository']=$to, 'phpgwapi'); - if ($to == 'univention') $to = 'ldap'; // there is no auth type "univention", just "ldap" if (empty($GLOBALS['egw_info']['server']['auth_type']) || $GLOBALS['egw_info']['server']['auth_type'] == $from) { Api\Config::save_value('auth_type', $GLOBALS['egw_info']['server']['auth_type']=$to, 'phpgwapi');