* Admin/Mail: fix admin editing (personal) mail account of other user destroys password, because it was encrypted with users session password and therefore not available

This commit is contained in:
Ralf Becker 2016-06-01 16:24:47 +02:00
parent 9f1c0c89b4
commit 06dee154d0
2 changed files with 39 additions and 4 deletions

View File

@ -1216,6 +1216,13 @@ class Account implements \ArrayAccess
// add imap credentials
$cred_type = $data['acc_imap_username'] == $data['acc_smtp_username'] &&
$data['acc_imap_password'] == $data['acc_smtp_password'] ? 3 : 1;
// if both passwords are unavailable, they seem identical, do NOT store them together, as they are not!
if ($cred_type == 3 && $data['acc_imap_password'] == Credentials::UNAVAILABLE &&
$data['acc_imap_password'] == Credentials::UNAVAILABLE &&
$data['acc_imap_cred_id'] != $data['acc_smtp_cred_id'])
{
$cred_type = 1;
}
Credentials::write($data['acc_id'], $data['acc_imap_username'], $data['acc_imap_password'],
$cred_type, $valid_for, $data['acc_imap_cred_id']);
// add smtp credentials if necessary and different from imap
@ -1225,6 +1232,11 @@ class Account implements \ArrayAccess
2, $valid_for, $data['acc_smtp_cred_id'] != $data['acc_imap_cred_id'] ?
$data['acc_smtp_cred_id'] : null);
}
// delete evtl. existing SMTP credentials, after storing IMAP&SMTP together now
elseif ($data['acc_smtp_cred_id'])
{
Credentials::delete($data['acc_id'], $valid_for, Credentials::SMTP, true);
}
// store or delete admin credentials
if ($data['acc_imap_admin_username'] && $data['acc_imap_admin_password'])
{
@ -1263,7 +1275,7 @@ class Account implements \ArrayAccess
*
* @param array|Account $account
* @param int $account_id =null
* @return boolean
* @return int account_id for whom credentials are valid or 0 for all
*/
protected static function credentials_valid_for($account, $account_id=null)
{

View File

@ -68,6 +68,11 @@ class Credentials
*/
const SYSTEM = 2;
/**
* Returned for passwords, when an admin reads an accounts with a password encrypted with users session password
*/
const UNAVAILABLE = '**unavailable**';
/**
* Translate type to prefix
*
@ -263,6 +268,12 @@ class Credentials
'cred_type' => $type,
'cred_pw_enc' => $pw_enc,
);
// check if password is unavailable (admin edits an account with password encrypted with users session PW) and NOT store it
if ($password == self::UNAVAILABLE)
{
error_log(__METHOD__."(".array2string(func_get_args()).") can NOT store unavailable password, storing without password!");
unset($data['cred_password'], $data['cred_pw_enc']);
}
//error_log(__METHOD__."($acc_id, '$username', '$password', $type, $account_id, $cred_id, $mcrypt) storing ".array2string($data).' '.function_backtrace());
if ($cred_id > 0)
{
@ -290,9 +301,10 @@ class Credentials
* @param int $acc_id
* @param int|array $account_id =null
* @param int $type =self::ALL self::IMAP, self::SMTP or self::ADMIN
* @param boolean $exact_type =false true: delete only cred_type=$type, false: delete cred_type&$type
* @return int number of rows deleted
*/
public static function delete($acc_id, $account_id=null, $type=self::ALL)
public static function delete($acc_id, $account_id=null, $type=self::ALL, $exact_type=false)
{
if (!($acc_id > 0) && !isset($account_id))
{
@ -301,8 +313,14 @@ class Credentials
$where = array();
if ($acc_id > 0) $where['acc_id'] = $acc_id;
if (isset($account_id)) $where['account_id'] = $account_id;
if ($type != self::ALL) $where[] = '(cred_type & '.(int)$type.') > 0'; // postgreSQL require > 0, or gives error as it expects boolean
if ($exact_type)
{
$where['cred_type'] = $type;
}
elseif ($type != self::ALL)
{
$where[] = '(cred_type & '.(int)$type.') > 0'; // postgreSQL require > 0, or gives error as it expects boolean
}
self::$db->delete(self::TABLE, $where, __LINE__, __FILE__, self::APP);
// invalidate cache: we allways unset everything about an account to simplify cache handling
@ -359,6 +377,11 @@ class Credentials
return base64_decode($row['cred_password']);
case self::USER:
if ($row['account_id'] != $GLOBALS['egw_info']['user']['account_id'])
{
return self::UNAVAILABLE;
}
// fall through
case self::SYSTEM:
if (($row['cred_pw_enc'] != self::USER || !$mcrypt) &&
!($mcrypt = self::init_crypt($row['cred_pw_enc'] == self::USER)))