|
1
|
|
|
<?php |
|
2
|
|
|
/** |
|
3
|
|
|
* EGroupware EMailAdmin: Mail account credentials |
|
4
|
|
|
* |
|
5
|
|
|
* @link http://www.stylite.de |
|
6
|
|
|
* @package emailadmin |
|
7
|
|
|
* @author Ralf Becker <[email protected]> |
|
8
|
|
|
* @copyright (c) 2013-14 by Ralf Becker <[email protected]> |
|
9
|
|
|
* @author Stylite AG <[email protected]> |
|
10
|
|
|
* @license http://opensource.org/licenses/gpl-license.php GPL - GNU General Public License |
|
11
|
|
|
* @version $Id$ |
|
12
|
|
|
*/ |
|
13
|
|
|
|
|
14
|
|
|
/** |
|
15
|
|
|
* Mail account credentials are stored in egw_ea_credentials for given |
|
16
|
|
|
* acocunt-id, users and types (imap, smtp and optional admin connection). |
|
17
|
|
|
* |
|
18
|
|
|
* Passwords in credentials are encrypted with either user password from session |
|
19
|
|
|
* or the database password. |
|
20
|
|
|
*/ |
|
21
|
|
|
class emailadmin_credentials |
|
22
|
|
|
{ |
|
23
|
|
|
const APP = 'emailadmin'; |
|
24
|
|
|
const TABLE = 'egw_ea_credentials'; |
|
25
|
|
|
const USER_EDITABLE_JOIN = 'JOIN egw_ea_accounts ON egw_ea_accounts.acc_id=egw_ea_credentials.acc_id AND acc_user_editable='; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* Credentials for type IMAP |
|
29
|
|
|
*/ |
|
30
|
|
|
const IMAP = 1; |
|
31
|
|
|
/** |
|
32
|
|
|
* Credentials for type SMTP |
|
33
|
|
|
*/ |
|
34
|
|
|
const SMTP = 2; |
|
35
|
|
|
/** |
|
36
|
|
|
* Credentials for admin connection |
|
37
|
|
|
*/ |
|
38
|
|
|
const ADMIN = 8; |
|
39
|
|
|
/** |
|
40
|
|
|
* All credentials IMAP|SMTP|ADMIN |
|
41
|
|
|
*/ |
|
42
|
|
|
const ALL = 11; |
|
43
|
|
|
|
|
44
|
|
|
/** |
|
45
|
|
|
* Password in cleartext |
|
46
|
|
|
*/ |
|
47
|
|
|
const CLEARTEXT = 0; |
|
48
|
|
|
/** |
|
49
|
|
|
* Password encrypted with user password |
|
50
|
|
|
*/ |
|
51
|
|
|
const USER = 1; |
|
52
|
|
|
/** |
|
53
|
|
|
* Password encrypted with system secret |
|
54
|
|
|
*/ |
|
55
|
|
|
const SYSTEM = 2; |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* Returned for passwords, when an admin reads an accounts with a password encrypted with users session password |
|
59
|
|
|
*/ |
|
60
|
|
|
const UNAVAILABLE = '**unavailable**'; |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* Translate type to prefix |
|
64
|
|
|
* |
|
65
|
|
|
* @var array |
|
66
|
|
|
*/ |
|
67
|
|
|
protected static $type2prefix = array( |
|
68
|
|
|
self::IMAP => 'acc_imap_', |
|
69
|
|
|
self::SMTP => 'acc_smtp_', |
|
70
|
|
|
self::ADMIN => 'acc_imap_admin_', |
|
71
|
|
|
); |
|
72
|
|
|
|
|
73
|
|
|
/** |
|
74
|
|
|
* Reference to global db object |
|
75
|
|
|
* |
|
76
|
|
|
* @var egw_db |
|
77
|
|
|
*/ |
|
78
|
|
|
static protected $db; |
|
79
|
|
|
|
|
80
|
|
|
/** |
|
81
|
|
|
* Mcrypt instance initialised with system specific key |
|
82
|
|
|
* |
|
83
|
|
|
* @var ressource |
|
84
|
|
|
*/ |
|
85
|
|
|
static protected $system_mcrypt; |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* Mcrypt instance initialised with user password from session |
|
89
|
|
|
* |
|
90
|
|
|
* @var ressource |
|
91
|
|
|
*/ |
|
92
|
|
|
static protected $user_mcrypt; |
|
93
|
|
|
|
|
94
|
|
|
/** |
|
95
|
|
|
* Cache for credentials to minimize database access |
|
96
|
|
|
* |
|
97
|
|
|
* @var array |
|
98
|
|
|
*/ |
|
99
|
|
|
protected static $cache = array(); |
|
100
|
|
|
|
|
101
|
|
|
/** |
|
102
|
|
|
* Read credentials for a given mail account |
|
103
|
|
|
* |
|
104
|
|
|
* @param int $acc_id |
|
105
|
|
|
* @param int $type =null default return all credentials |
|
106
|
|
|
* @param int|array $account_id =null default use current user or all (in that order) |
|
107
|
|
|
* @return array with values for (imap|smtp|admin)_(username|password|cred_id) |
|
108
|
|
|
*/ |
|
109
|
|
|
public static function read($acc_id, $type=null, $account_id=null) |
|
110
|
|
|
{ |
|
111
|
|
|
if (is_null($type)) $type = self::ALL; |
|
112
|
|
View Code Duplication |
if (is_null($account_id)) |
|
113
|
|
|
{ |
|
114
|
|
|
$account_id = array(0, $GLOBALS['egw_info']['user']['account_id']); |
|
115
|
|
|
} |
|
116
|
|
|
|
|
117
|
|
|
// check cache, if nothing found, query database |
|
118
|
|
|
// check assumes always same accounts (eg. 0=all plus own account_id) are asked |
|
119
|
|
|
if (!isset(self::$cache[$acc_id]) || |
|
120
|
|
|
!($rows = array_intersect_key(self::$cache[$acc_id], array_flip((array)$account_id)))) |
|
121
|
|
|
{ |
|
122
|
|
|
$rows = self::$db->select(self::TABLE, '*', array( |
|
123
|
|
|
'acc_id' => $acc_id, |
|
124
|
|
|
'account_id' => $account_id, |
|
125
|
|
|
'(cred_type & '.(int)$type.') > 0', // postgreSQL require > 0, or gives error as it expects boolean |
|
126
|
|
|
), __LINE__, __FILE__, false, |
|
127
|
|
|
// account_id DESC ensures 0=all allways overwrite (old user-specific credentials) |
|
128
|
|
|
'ORDER BY account_id ASC', self::APP); |
|
129
|
|
|
//error_log(__METHOD__."($acc_id, $type, ".array2string($account_id).") nothing in cache"); |
|
130
|
|
|
} |
|
131
|
|
|
else |
|
132
|
|
|
{ |
|
133
|
|
|
ksort($rows); // ORDER BY account_id ASC |
|
134
|
|
|
|
|
135
|
|
|
// flatten account_id => cred_type => row array again, to have format like from database |
|
136
|
|
|
$rows = call_user_func_array('array_merge', $rows); |
|
137
|
|
|
//error_log(__METHOD__."($acc_id, $type, ".array2string($account_id).") read from cache ".array2string($rows)); |
|
138
|
|
|
} |
|
139
|
|
|
$results = array(); |
|
140
|
|
|
foreach($rows as $row) |
|
141
|
|
|
{ |
|
142
|
|
|
// update cache (only if we have database-iterator and all credentials asked!) |
|
143
|
|
|
if (!is_array($rows) && $type == self::ALL) |
|
144
|
|
|
{ |
|
145
|
|
|
self::$cache[$acc_id][$row['account_id']][$row['cred_type']] = $row; |
|
146
|
|
|
//error_log(__METHOD__."($acc_id, $type, ".array2string($account_id).") stored to cache ".array2string($row)); |
|
147
|
|
|
} |
|
148
|
|
|
$password = self::decrypt($row); |
|
149
|
|
|
|
|
150
|
|
|
foreach(self::$type2prefix as $pattern => $prefix) |
|
151
|
|
|
{ |
|
152
|
|
|
if ($row['cred_type'] & $pattern) |
|
153
|
|
|
{ |
|
154
|
|
|
$results[$prefix.'username'] = $row['cred_username']; |
|
155
|
|
|
$results[$prefix.'password'] = $password; |
|
156
|
|
|
$results[$prefix.'cred_id'] = $row['cred_id']; |
|
157
|
|
|
$results[$prefix.'account_id'] = $row['account_id']; |
|
158
|
|
|
$results[$prefix.'pw_enc'] = $row['cred_pw_enc']; |
|
159
|
|
|
} |
|
160
|
|
|
} |
|
161
|
|
|
} |
|
162
|
|
|
return $results; |
|
163
|
|
|
} |
|
164
|
|
|
|
|
165
|
|
|
/** |
|
166
|
|
|
* Generate username according to acc_imap_logintype and fetch password from session |
|
167
|
|
|
* |
|
168
|
|
|
* @param array $data values for acc_imap_logintype and acc_domain |
|
169
|
|
|
* @param boolean $set_identity =true true: also set identity values realname&email, if not yet set |
|
170
|
|
|
* @return array with values for keys 'acc_(imap|smtp)_(username|password|cred_id)' |
|
171
|
|
|
*/ |
|
172
|
|
|
public static function from_session(array $data, $set_identity=true) |
|
173
|
|
|
{ |
|
174
|
|
|
switch($data['acc_imap_logintype']) |
|
175
|
|
|
{ |
|
176
|
|
|
case 'standard': |
|
177
|
|
|
$username = $GLOBALS['egw_info']['user']['account_lid']; |
|
178
|
|
|
break; |
|
179
|
|
|
|
|
180
|
|
|
case 'vmailmgr': |
|
181
|
|
|
$username = $GLOBALS['egw_info']['user']['account_lid'].'@'.$data['acc_domain']; |
|
182
|
|
|
break; |
|
183
|
|
|
|
|
184
|
|
|
case 'email': |
|
185
|
|
|
$username = $GLOBALS['egw_info']['user']['account_email']; |
|
186
|
|
|
break; |
|
187
|
|
|
|
|
188
|
|
|
case 'uidNumber': |
|
189
|
|
|
$username = 'u'.$GLOBALS['egw_info']['user']['account_id'].'@'.$data['acc_domain']; |
|
190
|
|
|
break; |
|
191
|
|
|
|
|
192
|
|
|
case 'admin': |
|
193
|
|
|
// data should have been stored in credentials table |
|
194
|
|
|
throw new egw_exception_assertion_failed('data[acc_imap_logintype]=admin and no stored username/password for data[acc_id]='.$data['acc_id'].'!'); |
|
195
|
|
|
|
|
196
|
|
|
default: |
|
197
|
|
|
throw new egw_exception_wrong_parameter("Unknown data[acc_imap_logintype]=".array2string($data['acc_imap_logintype']).'!'); |
|
198
|
|
|
} |
|
199
|
|
|
$password = base64_decode(egw_cache::getSession('phpgwapi', 'password')); |
|
200
|
|
|
$realname = !$set_identity || $data['ident_realname'] ? $data['ident_realname'] : |
|
201
|
|
|
$GLOBALS['egw_info']['user']['account_fullname']; |
|
202
|
|
|
$email = !$set_identity || $data['ident_email'] ? $data['ident_email'] : |
|
203
|
|
|
$GLOBALS['egw_info']['user']['account_email']; |
|
204
|
|
|
|
|
205
|
|
|
return array( |
|
206
|
|
|
'ident_realname' => $realname, |
|
207
|
|
|
'ident_email' => $email, |
|
208
|
|
|
'acc_imap_username' => $username, |
|
209
|
|
|
'acc_imap_password' => $password, |
|
210
|
|
|
'acc_imap_cred_id' => $data['acc_imap_logintype'], // to NOT store it |
|
211
|
|
|
'acc_imap_account_id' => 'c', |
|
212
|
|
|
) + ($data['acc_smtp_auth_session'] ? array( |
|
213
|
|
|
// only set smtp |
|
214
|
|
|
'acc_smtp_username' => $username, |
|
215
|
|
|
'acc_smtp_password' => $password, |
|
216
|
|
|
'acc_smtp_cred_id' => $data['acc_imap_logintype'], // to NOT store it |
|
217
|
|
|
'acc_smtp_account_id' => 'c', |
|
218
|
|
|
) : array()); |
|
219
|
|
|
} |
|
220
|
|
|
|
|
221
|
|
|
/** |
|
222
|
|
|
* Write and encrypt credentials |
|
223
|
|
|
* |
|
224
|
|
|
* @param int $acc_id id of account |
|
225
|
|
|
* @param string $username |
|
226
|
|
|
* @param string $password cleartext password to write |
|
227
|
|
|
* @param int $type self::IMAP, self::SMTP or self::ADMIN |
|
228
|
|
|
* @param int $account_id if of user-account for whom credentials are |
|
229
|
|
|
* @param int $cred_id =null id of existing credentials to update |
|
230
|
|
|
* @param ressource $mcrypt =null mcrypt ressource for user, default calling self::init_crypt(true) |
|
231
|
|
|
* @return int cred_id |
|
232
|
|
|
*/ |
|
233
|
|
|
public static function write($acc_id, $username, $password, $type, $account_id=0, $cred_id=null, $mcrypt=null) |
|
234
|
|
|
{ |
|
235
|
|
|
//error_log(__METHOD__."(acc_id=$acc_id, '$username', \$password, type=$type, account_id=$account_id, cred_id=$cred_id)"); |
|
236
|
|
|
if (!empty($cred_id) && !is_numeric($cred_id) || !is_numeric($account_id)) |
|
237
|
|
|
{ |
|
238
|
|
|
//error_log(__METHOD__."($acc_id, '$username', \$password, $type, $account_id, ".array2string($cred_id).") not storing session credentials!"); |
|
239
|
|
|
return; // do NOT store credentials from session of current user! |
|
240
|
|
|
} |
|
241
|
|
|
// no need to write empty usernames, but delete existing row |
|
242
|
|
|
if ((string)$username === '') |
|
243
|
|
|
{ |
|
244
|
|
|
if ($cred_id) self::$db->delete(self::TABLE, array('cred_id' => $cred_id), __LINE__, __FILE__, self::APP); |
|
245
|
|
|
return; // nothing to save |
|
246
|
|
|
} |
|
247
|
|
|
$pw_enc = self::CLEARTEXT; |
|
248
|
|
|
$data = array( |
|
249
|
|
|
'acc_id' => $acc_id, |
|
250
|
|
|
'account_id' => $account_id, |
|
251
|
|
|
'cred_username' => $username, |
|
252
|
|
|
'cred_password' => (string)$password === '' ? '' : |
|
253
|
|
|
self::encrypt($password, $account_id, $pw_enc, $mcrypt), |
|
254
|
|
|
'cred_type' => $type, |
|
255
|
|
|
'cred_pw_enc' => $pw_enc, |
|
256
|
|
|
); |
|
257
|
|
|
// check if password is unavailable (admin edits an account with password encrypted with users session PW) and NOT store it |
|
258
|
|
|
if ($password == self::UNAVAILABLE) |
|
259
|
|
|
{ |
|
260
|
|
|
//error_log(__METHOD__."(".array2string(func_get_args()).") can NOT store unavailable password, storing without password!"); |
|
261
|
|
|
unset($data['cred_password'], $data['cred_pw_enc']); |
|
262
|
|
|
} |
|
263
|
|
|
//error_log(__METHOD__."($acc_id, '$username', '$password', $type, $account_id, $cred_id, $mcrypt) storing ".array2string($data).' '.function_backtrace()); |
|
264
|
|
|
if ($cred_id > 0) |
|
265
|
|
|
{ |
|
266
|
|
|
self::$db->update(self::TABLE, $data, array('cred_id' => $cred_id), __LINE__, __FILE__, self::APP); |
|
267
|
|
|
} |
|
268
|
|
|
else |
|
269
|
|
|
{ |
|
270
|
|
|
self::$db->insert(self::TABLE, $data, array( |
|
271
|
|
|
'acc_id' => $acc_id, |
|
272
|
|
|
'account_id' => $account_id, |
|
273
|
|
|
'cred_type' => $type, |
|
274
|
|
|
), __LINE__, __FILE__, self::APP); |
|
275
|
|
|
$cred_id = self::$db->get_last_insert_id(self::TABLE, 'cred_id'); |
|
276
|
|
|
} |
|
277
|
|
|
// invalidate cache |
|
278
|
|
|
unset(self::$cache[$acc_id][$account_id]); |
|
279
|
|
|
|
|
280
|
|
|
//error_log(__METHOD__."($acc_id, '$username', \$password, $type, $account_id) returning $cred_id"); |
|
281
|
|
|
return $cred_id; |
|
282
|
|
|
} |
|
283
|
|
|
|
|
284
|
|
|
/** |
|
285
|
|
|
* Delete credentials from database |
|
286
|
|
|
* |
|
287
|
|
|
* @param int $acc_id |
|
288
|
|
|
* @param int|array $account_id =null |
|
289
|
|
|
* @param int $type =self::ALL self::IMAP, self::SMTP or self::ADMIN |
|
290
|
|
|
* @param boolean $exact_type =false true: delete only cred_type=$type, false: delete cred_type&$type |
|
291
|
|
|
* @return int number of rows deleted |
|
292
|
|
|
*/ |
|
293
|
|
|
public static function delete($acc_id, $account_id=null, $type=self::ALL, $exact_type=false) |
|
294
|
|
|
{ |
|
295
|
|
|
if (!($acc_id > 0) && !isset($account_id)) |
|
296
|
|
|
{ |
|
297
|
|
|
throw new egw_exception_wrong_parameter(__METHOD__."() no acc_id AND no account_id parameter!"); |
|
298
|
|
|
} |
|
299
|
|
|
$where = array(); |
|
300
|
|
|
if ($acc_id > 0) $where['acc_id'] = $acc_id; |
|
301
|
|
|
if (isset($account_id)) $where['account_id'] = $account_id; |
|
302
|
|
|
if ($exact_type) |
|
303
|
|
|
{ |
|
304
|
|
|
$where['cred_type'] = $type; |
|
305
|
|
|
} |
|
306
|
|
|
elseif ($type != self::ALL) |
|
307
|
|
|
{ |
|
308
|
|
|
$where[] = '(cred_type & '.(int)$type.') > 0'; // postgreSQL require > 0, or gives error as it expects boolean |
|
309
|
|
|
} |
|
310
|
|
|
self::$db->delete(self::TABLE, $where, __LINE__, __FILE__, self::APP); |
|
311
|
|
|
|
|
312
|
|
|
// invalidate cache: we allways unset everything about an account to simplify cache handling |
|
313
|
|
View Code Duplication |
foreach($acc_id > 0 ? (array)$acc_id : array_keys(self::$cache) as $acc_id) |
|
314
|
|
|
{ |
|
315
|
|
|
unset(self::$cache[$acc_id]); |
|
316
|
|
|
} |
|
317
|
|
|
$ret = self::$db->affected_rows(); |
|
318
|
|
|
//error_log(__METHOD__."($acc_id, ".array2string($account_id).", $type) affected $ret rows"); |
|
319
|
|
|
return $ret; |
|
320
|
|
|
} |
|
321
|
|
|
|
|
322
|
|
|
/** |
|
323
|
|
|
* Encrypt password for storing in database |
|
324
|
|
|
* |
|
325
|
|
|
* @param string $password cleartext password |
|
326
|
|
|
* @param int $account_id user-account password is for |
|
327
|
|
|
* @param int &$pw_enc on return encryption used |
|
328
|
|
|
* @param ressource $mcrypt =null mcrypt ressource for user, default calling self::init_crypt(true) |
|
329
|
|
|
* @return string encrypted password |
|
330
|
|
|
*/ |
|
331
|
|
|
protected static function encrypt($password, $account_id, &$pw_enc, $mcrypt=null) |
|
332
|
|
|
{ |
|
333
|
|
|
if ($account_id > 0 && $account_id == $GLOBALS['egw_info']['user']['account_id'] && |
|
334
|
|
|
($mcrypt || ($mcrypt = self::init_crypt(true)))) |
|
335
|
|
|
{ |
|
336
|
|
|
$pw_enc = self::USER; |
|
337
|
|
|
$password = mcrypt_generic($mcrypt, $password); |
|
338
|
|
|
} |
|
339
|
|
|
elseif (($mcrypt = self::init_crypt(false))) |
|
340
|
|
|
{ |
|
341
|
|
|
$pw_enc = self::SYSTEM; |
|
342
|
|
|
$password = mcrypt_generic($mcrypt, $password); |
|
343
|
|
|
} |
|
344
|
|
|
else |
|
345
|
|
|
{ |
|
346
|
|
|
$pw_enc = self::CLEARTEXT; |
|
347
|
|
|
} |
|
348
|
|
|
//error_log(__METHOD__."(, $account_id, , $mcrypt) pw_enc=$pw_enc returning ".array2string(base64_encode($password))); |
|
349
|
|
|
return base64_encode($password); |
|
350
|
|
|
} |
|
351
|
|
|
|
|
352
|
|
|
/** |
|
353
|
|
|
* Decrypt password from database |
|
354
|
|
|
* |
|
355
|
|
|
* @param array $row database row |
|
356
|
|
|
* @param ressource $mcrypt =null mcrypt ressource for user, default calling self::init_crypt(true) |
|
357
|
|
|
*/ |
|
358
|
|
|
protected static function decrypt(array $row, $mcrypt=null) |
|
359
|
|
|
{ |
|
360
|
|
|
switch ($row['cred_pw_enc']) |
|
361
|
|
|
{ |
|
362
|
|
|
case self::CLEARTEXT: |
|
363
|
|
|
return base64_decode($row['cred_password']); |
|
364
|
|
|
|
|
365
|
|
|
case self::USER: |
|
366
|
|
|
if ($row['account_id'] != $GLOBALS['egw_info']['user']['account_id']) |
|
367
|
|
|
{ |
|
368
|
|
|
return self::UNAVAILABLE; |
|
369
|
|
|
} |
|
370
|
|
|
// fall through |
|
371
|
|
|
case self::SYSTEM: |
|
372
|
|
|
if (($row['cred_pw_enc'] != self::USER || !$mcrypt) && |
|
373
|
|
|
!($mcrypt = self::init_crypt($row['cred_pw_enc'] == self::USER))) |
|
374
|
|
|
{ |
|
375
|
|
|
throw new egw_exception_wrong_parameter("Password encryption type $row[cred_pw_enc] NOT available for mail account #$row[acc_id] and user #$row[account_id]/$row[cred_username]!"); |
|
376
|
|
|
} |
|
377
|
|
|
return !empty($row['cred_password']) ? trim(mdecrypt_generic($mcrypt, base64_decode($row['cred_password']))) : ''; |
|
378
|
|
|
} |
|
379
|
|
|
throw new egw_exception_wrong_parameter("Unknow password encryption type $row[cred_pw_enc]!"); |
|
380
|
|
|
} |
|
381
|
|
|
|
|
382
|
|
|
/** |
|
383
|
|
|
* Hook called when user changes his password, to re-encode his credentials with his new password |
|
384
|
|
|
* |
|
385
|
|
|
* It also changes all user credentials encoded with system password! |
|
386
|
|
|
* |
|
387
|
|
|
* It only changes credentials from user-editable accounts, as user probably |
|
388
|
|
|
* does NOT know password set by admin! |
|
389
|
|
|
* |
|
390
|
|
|
* @param array $data values for keys 'old_passwd', 'new_passwd', 'account_id' |
|
391
|
|
|
*/ |
|
392
|
|
|
static public function changepassword(array $data) |
|
393
|
|
|
{ |
|
394
|
|
|
if (empty($data['old_passwd'])) return; |
|
395
|
|
|
|
|
396
|
|
|
$old_mcrypt = null; |
|
397
|
|
|
foreach(self::$db->select(self::TABLE, self::TABLE.'.*', array( |
|
398
|
|
|
'account_id' => $data['account_id'] |
|
399
|
|
|
),__LINE__, __FILE__, false, '', 'emailadmin', 0, self::USER_EDITABLE_JOIN.self::$db->quote(true, 'bool')) as $row) |
|
400
|
|
|
{ |
|
401
|
|
|
if (!isset($old_mcrypt)) |
|
402
|
|
|
{ |
|
403
|
|
|
$old_mcrypt = self::init_crypt($data['old_passwd']); |
|
404
|
|
|
$new_mcrypt = self::init_crypt($data['new_passwd']); |
|
405
|
|
|
if (!$old_mcrypt && !$new_mcrypt) return; |
|
406
|
|
|
} |
|
407
|
|
|
$password = self::decrypt($row, $old_mcrypt); |
|
|
|
|
|
|
408
|
|
|
|
|
409
|
|
|
self::write($row['acc_id'], $row['cred_username'], $password, $row['cred_type'], |
|
410
|
|
|
$row['account_id'], $row['cred_id'], $new_mcrypt); |
|
|
|
|
|
|
411
|
|
|
} |
|
412
|
|
|
} |
|
413
|
|
|
|
|
414
|
|
|
/** |
|
415
|
|
|
* Check if session encryption is configured, possible and initialise it |
|
416
|
|
|
* |
|
417
|
|
|
* @param boolean|string $user =false true: use user-password from session, |
|
418
|
|
|
* false: database password or string with password to use |
|
419
|
|
|
* @param string $algo ='tripledes' |
|
420
|
|
|
* @param string $mode ='ecb' |
|
421
|
|
|
* @return ressource|boolean mcrypt ressource to use or false if not available |
|
422
|
|
|
*/ |
|
423
|
|
|
static public function init_crypt($user=false, $algo='tripledes',$mode='ecb') |
|
424
|
|
|
{ |
|
425
|
|
|
if (is_string($user)) |
|
|
|
|
|
|
426
|
|
|
{ |
|
427
|
|
|
// do NOT use/set/change static object |
|
428
|
|
|
} |
|
429
|
|
|
elseif ($user) |
|
430
|
|
|
{ |
|
431
|
|
|
$mcrypt =& self::$user_mcrypt; |
|
432
|
|
|
} |
|
433
|
|
|
else |
|
434
|
|
|
{ |
|
435
|
|
|
$mcrypt =& self::$system_mcrypt; |
|
436
|
|
|
} |
|
437
|
|
|
if (!isset($mcrypt)) |
|
438
|
|
|
{ |
|
439
|
|
|
if (is_string($user)) |
|
440
|
|
|
{ |
|
441
|
|
|
$key = $user; |
|
442
|
|
|
} |
|
443
|
|
|
elseif ($user) |
|
444
|
|
|
{ |
|
445
|
|
|
$session_key = egw_cache::getSession('phpgwapi', 'password'); |
|
446
|
|
|
if (empty($session_key)) |
|
447
|
|
|
{ |
|
448
|
|
|
error_log(__METHOD__."() no session password available!"); |
|
449
|
|
|
return false; |
|
450
|
|
|
} |
|
451
|
|
|
$key = base64_decode($session_key); |
|
452
|
|
|
} |
|
453
|
|
|
else |
|
454
|
|
|
{ |
|
455
|
|
|
$key = self::$db->Password; |
|
456
|
|
|
} |
|
457
|
|
|
if (!check_load_extension('mcrypt')) |
|
458
|
|
|
{ |
|
459
|
|
|
error_log(__METHOD__."() required PHP extension mcrypt not loaded and can not be loaded, passwords can be NOT encrypted!"); |
|
460
|
|
|
$mcrypt = false; |
|
461
|
|
|
} |
|
462
|
|
|
elseif (!($mcrypt = mcrypt_module_open($algo, '', $mode, ''))) |
|
463
|
|
|
{ |
|
464
|
|
|
error_log(__METHOD__."() could not mcrypt_module_open(algo='$algo','',mode='$mode',''), passwords can be NOT encrypted!"); |
|
465
|
|
|
$mcrypt = false; |
|
466
|
|
|
} |
|
467
|
|
|
else |
|
468
|
|
|
{ |
|
469
|
|
|
$iv_size = mcrypt_enc_get_iv_size($mcrypt); |
|
470
|
|
|
$iv = !isset($GLOBALS['egw_info']['server']['mcrypt_iv']) || strlen($GLOBALS['egw_info']['server']['mcrypt_iv']) < $iv_size ? |
|
471
|
|
|
mcrypt_create_iv ($iv_size, MCRYPT_RAND) : substr($GLOBALS['egw_info']['server']['mcrypt_iv'],0,$iv_size); |
|
472
|
|
|
|
|
473
|
|
|
$key_size = mcrypt_enc_get_key_size($mcrypt); |
|
474
|
|
|
if (bytes($key) > $key_size) $key = cut_bytes($key,0,$key_size-1); |
|
475
|
|
|
|
|
476
|
|
|
if (mcrypt_generic_init($mcrypt, $key, $iv) < 0) |
|
477
|
|
|
{ |
|
478
|
|
|
error_log(__METHOD__."() could not initialise mcrypt, passwords can be NOT encrypted!"); |
|
479
|
|
|
$mcrypt = false; |
|
480
|
|
|
} |
|
481
|
|
|
} |
|
482
|
|
|
} |
|
483
|
|
|
//error_log(__METHOD__."(".array2string($user).") key=".array2string($key)." returning ".array2string($mcrypt)); |
|
484
|
|
|
return $mcrypt; |
|
485
|
|
|
} |
|
486
|
|
|
|
|
487
|
|
|
/** |
|
488
|
|
|
* Init our static properties |
|
489
|
|
|
*/ |
|
490
|
|
|
static public function init_static() |
|
491
|
|
|
{ |
|
492
|
|
|
self::$db = isset($GLOBALS['egw_setup']) ? $GLOBALS['egw_setup']->db : $GLOBALS['egw']->db; |
|
493
|
|
|
} |
|
494
|
|
|
} |
|
495
|
|
|
emailadmin_credentials::init_static(); |
|
496
|
|
|
|
This check looks for type mismatches where the missing type is
false. This is usually indicative of an error condtion.Consider the follow example
This function either returns a new
DateTimeobject or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returnedfalsebefore passing on the value to another function or method that may not be able to handle afalse.