Passed
Push — teampass_3.0 ( fe73e4...8b0342 )
by Nils
03:34
created

ldapPosixAndWindows()   B

Complexity

Conditions 8
Paths 32

Size

Total Lines 80
Code Lines 50

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 8
eloc 50
c 0
b 0
f 0
nc 32
nop 3
dl 0
loc 80
rs 7.8464

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/**
3
 * @author        Nils Laumaillé <[email protected]>
4
 *
5
 * @version       2.1.27
6
 *
7
 * @copyright     2009-2018 Nils Laumaillé
8
 * @license       GNU GPL-3.0
9
 *
10
 * @see
11
 */
12
13
//define pbkdf2 iteration count
14
define('ITCOUNT', '2072');
15
16
if (!isset($_SESSION['CPM']) || $_SESSION['CPM'] != 1) {
17
    die('Hacking attempt...');
18
}
19
20
// Load config if $SETTINGS not defined
21
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
22
    if (file_exists('../includes/config/tp.config.php')) {
23
        include_once '../includes/config/tp.config.php';
24
    } elseif (file_exists('./includes/config/tp.config.php')) {
25
        include_once './includes/config/tp.config.php';
26
    } elseif (file_exists('../../includes/config/tp.config.php')) {
27
        include_once '../../includes/config/tp.config.php';
28
    } else {
29
        throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
30
    }
31
}
32
33
// load phpCrypt
34
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
35
    include_once '../includes/libraries/phpcrypt/phpCrypt.php';
36
    include_once '../includes/config/settings.php';
37
} else {
38
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/phpcrypt/phpCrypt.php';
39
    include_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
40
}
41
42
header('Content-type: text/html; charset=utf-8');
43
header('Cache-Control: no-cache, must-revalidate');
44
45
// Prepare PHPCrypt class calls
46
use PHP_Crypt\PHP_Crypt as PHP_Crypt;
47
// Prepare Encryption class calls
48
use Defuse\Crypto\Crypto;
49
50
/**
51
 * Undocumented function.
52
 *
53
 * @param [type] $string
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
54
 */
55
function langHdl($string)
56
{
57
    if (empty($string) === true || isset($_SESSION['teampass']['lang'][$string]) === false) {
58
        // Manage error
59
    } else {
60
        return str_replace(
61
            array('"', "'"),
62
            array('&quot;', '&apos;'),
63
            $_SESSION['teampass']['lang'][$string]
64
        );
65
    }
66
}
67
68
//Generate N# of random bits for use as salt
69
/**
70
 * @param int $size
71
 */
72
function getBits($size)
73
{
74
    $str = '';
75
    $var_x = $size + 10;
76
    for ($var_i = 0; $var_i < $var_x; ++$var_i) {
77
        $str .= base_convert(mt_rand(1, 36), 10, 36);
78
    }
79
80
    return substr($str, 0, $size);
81
}
82
83
//generate pbkdf2 compliant hash
84
function strHashPbkdf2($var_p, $var_s, $var_c, $var_kl, $var_a = 'sha256', $var_st = 0)
85
{
86
    $var_kb = $var_st + $var_kl; // Key blocks to compute
87
    $var_dk = ''; // Derived key
88
89
    for ($block = 1; $block <= $var_kb; ++$block) { // Create key
90
        $var_ib = $var_h = hash_hmac($var_a, $var_s.pack('N', $block), $var_p, true); // Initial hash for this block
91
        for ($var_i = 1; $var_i < $var_c; ++$var_i) { // Perform block iterations
92
            $var_ib ^= ($var_h = hash_hmac($var_a, $var_h, $var_p, true)); // XOR each iterate
93
        }
94
        $var_dk .= $var_ib; // Append iterated block
95
    }
96
97
    return substr($var_dk, $var_st, $var_kl); // Return derived key of correct length
98
}
99
100
/**
101
 * stringUtf8Decode().
102
 *
103
 * utf8_decode
104
 */
105
function stringUtf8Decode($string)
106
{
107
    return str_replace(' ', '+', utf8_decode($string));
108
}
109
110
/**
111
 * encryptOld().
112
 *
113
 * crypt a string
114
 *
115
 * @param string $text
116
 */
117
function encryptOld($text, $personalSalt = '')
118
{
119
    if (empty($personalSalt) === false) {
120
        return trim(
121
            base64_encode(
122
                mcrypt_encrypt(
1 ignored issue
show
Deprecated Code introduced by
The function mcrypt_encrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

122
                /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
123
                    MCRYPT_RIJNDAEL_256,
124
                    $personalSalt,
125
                    $text,
126
                    MCRYPT_MODE_ECB,
127
                    mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

127
                    /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
128
                        mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

128
                        /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
129
                        MCRYPT_RAND
130
                    )
131
                )
132
            )
133
        );
134
    }
135
136
    // If $personalSalt is not empty
137
    return trim(
138
        base64_encode(
139
            mcrypt_encrypt(
1 ignored issue
show
Deprecated Code introduced by
The function mcrypt_encrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

139
            /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
140
                MCRYPT_RIJNDAEL_256,
141
                SALT,
142
                $text,
143
                MCRYPT_MODE_ECB,
144
                mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

144
                /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
145
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

145
                    /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
146
                    MCRYPT_RAND
147
                )
148
            )
149
        )
150
    );
151
}
152
153
/**
154
 * decryptOld().
155
 *
156
 * decrypt a crypted string
157
 */
158
function decryptOld($text, $personalSalt = '')
159
{
160
    if (!empty($personalSalt)) {
161
        return trim(
162
            mcrypt_decrypt(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

162
            /** @scrutinizer ignore-deprecated */ mcrypt_decrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
163
                MCRYPT_RIJNDAEL_256,
164
                $personalSalt,
165
                base64_decode($text),
166
                MCRYPT_MODE_ECB,
167
                mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

167
                /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
168
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

168
                    /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
169
                    MCRYPT_RAND
170
                )
171
            )
172
        );
173
    }
174
175
    // No personal SK
176
    return trim(
177
        mcrypt_decrypt(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

177
        /** @scrutinizer ignore-deprecated */ mcrypt_decrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
178
            MCRYPT_RIJNDAEL_256,
179
            SALT,
180
            base64_decode($text),
181
            MCRYPT_MODE_ECB,
182
            mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

182
            /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
183
                mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

183
                /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
184
                MCRYPT_RAND
185
            )
186
        )
187
    );
188
}
189
190
/**
191
 * encrypt().
192
 *
193
 * crypt a string
194
 *
195
 * @param string $decrypted
196
 */
197
function encrypt($decrypted, $personalSalt = '')
198
{
199
    global $SETTINGS;
200
201
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
202
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
203
    } else {
204
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
205
    }
206
207
    if (!empty($personalSalt)) {
208
        $staticSalt = $personalSalt;
209
    } else {
210
        $staticSalt = SALT;
211
    }
212
213
    //set our salt to a variable
214
    // Get 64 random bits for the salt for pbkdf2
215
    $pbkdf2Salt = getBits(64);
216
    // generate a pbkdf2 key to use for the encryption.
217
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
218
    // Build $init_vect and $ivBase64.  We use a block size of 256 bits (AES compliant)
219
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
220
    $init_vect = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

220
    $init_vect = /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

220
    $init_vect = mcrypt_create_iv(/** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
221
222
    //base64 trim
223
    if (strlen($ivBase64 = rtrim(base64_encode($init_vect), '=')) != 43) {
224
        return false;
225
    }
226
    // Encrypt $decrypted
227
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $init_vect);
1 ignored issue
show
Deprecated Code introduced by
The function mcrypt_encrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

227
    $encrypted = /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $init_vect);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
228
    // MAC the encrypted text
229
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
230
    // We're done!
231
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
232
}
233
234
/**
235
 * decrypt().
236
 *
237
 * decrypt a crypted string
238
 */
239
function decrypt($encrypted, $personalSalt = '')
240
{
241
    global $SETTINGS;
242
243
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
244
        include_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
245
    } else {
246
        include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
247
    }
248
249
    if (!empty($personalSalt)) {
250
        $staticSalt = $personalSalt;
251
    } else {
252
        $staticSalt = file_get_contents(SECUREPATH.'/teampass-seckey.txt');
253
    }
254
    //base64 decode the entire payload
255
    $encrypted = base64_decode($encrypted);
256
    // get the salt
257
    $pbkdf2Salt = substr($encrypted, -64);
258
    //remove the salt from the string
259
    $encrypted = substr($encrypted, 0, -64);
260
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
261
    // Retrieve $init_vect which is the first 22 characters plus ==, base64_decoded.
262
    $init_vect = base64_decode(substr($encrypted, 0, 43).'==');
263
    // Remove $init_vect from $encrypted.
264
    $encrypted = substr($encrypted, 43);
265
    // Retrieve $mac which is the last 64 characters of $encrypted.
266
    $mac = substr($encrypted, -64);
267
    // Remove the last 64 chars from encrypted (remove MAC)
268
    $encrypted = substr($encrypted, 0, -64);
269
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
270
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
271
        return false;
272
    }
273
    // Decrypt the data.
274
    $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $init_vect), "\0\4");
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

274
    $decrypted = rtrim(/** @scrutinizer ignore-deprecated */ mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $init_vect), "\0\4");

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
275
    // Yay!
276
    return $decrypted;
277
}
278
279
/**
280
 * genHash().
281
 *
282
 * Generate a hash for user login
283
 *
284
 * @param string $password
285
 */
286
function bCrypt($password, $cost)
287
{
288
    $salt = sprintf('$2y$%02d$', $cost);
289
    if (function_exists('openssl_random_pseudo_bytes')) {
290
        $salt .= bin2hex(openssl_random_pseudo_bytes(11));
291
    } else {
292
        $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
293
        for ($i = 0; $i < 22; ++$i) {
294
            $salt .= $chars[mt_rand(0, 63)];
295
        }
296
    }
297
298
    return crypt($password, $salt);
299
}
300
301
/*
302
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
303
 *
304
 * Using AES_128 and mode CBC
305
 *
306
 * $key and $init_vect have to be given in hex format
307
 */
308
function cryption_phpCrypt($string, $key, $init_vect, $type)
309
{
310
    // manage key origin
311
    if (null != SALT && $key != SALT) {
312
        // check key (AES-128 requires a 16 bytes length key)
313
        if (strlen($key) < 16) {
314
            for ($inc = strlen($key) + 1; $inc <= 16; ++$inc) {
315
                $key .= chr(0);
316
            }
317
        } elseif (strlen($key) > 16) {
318
            $key = substr($key, 16);
319
        }
320
    }
321
322
    // load crypt
323
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
324
325
    if ($type === 'encrypt') {
326
        // generate IV and encrypt
327
        $init_vect = $crypt->createIV();
328
        $encrypt = $crypt->encrypt($string);
329
        // return
330
        return array(
331
            'string' => bin2hex($encrypt),
332
            'iv' => bin2hex($init_vect),
333
            'error' => empty($encrypt) ? 'ERR_ENCRYPTION_NOT_CORRECT' : '',
334
        );
335
    } elseif ($type === 'decrypt') {
336
        // case if IV is empty
337
        if (empty($init_vect)) {
338
            return array(
339
                'string' => '',
340
                'error' => 'ERR_ENCRYPTION_NOT_CORRECT',
341
            );
342
        }
343
344
        // convert
345
        try {
346
            $string = testHex2Bin(trim($string));
347
            $init_vect = testHex2Bin($init_vect);
348
        } catch (Exception $e) {
349
            return array(
350
                'string' => '',
351
                'error' => 'ERR_ENCRYPTION_NOT_CORRECT',
352
            );
353
        }
354
355
        // load IV
356
        $crypt->IV($init_vect);
357
        // decrypt
358
        $decrypt = $crypt->decrypt($string);
359
        // return
360
        return array(
361
            'string' => str_replace(chr(0), '', $decrypt),
362
            'error' => '',
363
        );
364
    }
365
}
366
367
function testHex2Bin($val)
368
{
369
    if (!@hex2bin($val)) {
370
        throw new Exception('ERROR');
371
    }
372
373
    return hex2bin($val);
374
}
375
376
/**
377
 * Defuse cryption function.
378
 *
379
 * @param string $message   what to de/crypt
380
 * @param string $ascii_key key to use
381
 * @param string $type      operation to perform
382
 * @param array  $SETTINGS  Teampass settings
383
 *
384
 * @return array
385
 */
386
function cryption($message, $ascii_key, $type, $SETTINGS)
387
{
388
    // load PhpEncryption library
389
    if (isset($SETTINGS['cpassman_dir']) === false || empty($SETTINGS['cpassman_dir']) === true) {
390
        $path = '../includes/libraries/Encryption/Encryption/';
391
    } else {
392
        $path = $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
393
    }
394
395
    include_once $path.'Crypto.php';
396
    include_once $path.'Encoding.php';
397
    include_once $path.'DerivedKeys.php';
398
    include_once $path.'Key.php';
399
    include_once $path.'KeyOrPassword.php';
400
    include_once $path.'File.php';
401
    include_once $path.'RuntimeTests.php';
402
    include_once $path.'KeyProtectedByPassword.php';
403
    include_once $path.'Core.php';
404
405
    // init
406
    $err = '';
407
    if (empty($ascii_key) === true) {
408
        $ascii_key = file_get_contents(SECUREPATH.'/teampass-seckey.txt');
409
    }
410
    
411
    // convert KEY
412
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
413
414
    try {
415
        if ($type === 'encrypt') {
416
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
417
        } elseif ($type === 'decrypt') {
418
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
419
        }
420
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
421
        $err = 'an attack! either the wrong key was loaded, or the ciphertext has changed since it was created either corrupted in the database or intentionally modified by someone trying to carry out an attack.';
422
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
423
        $err = $ex;
424
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
425
        $err = $ex;
426
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
427
        $err = $ex;
428
    } catch (Defuse\Crypto\Exception\IOException $ex) {
429
        $err = $ex;
430
    }
431
432
    return array(
433
        'string' => isset($text) ? $text : '',
434
        'error' => $err,
435
    );
436
}
437
438
/**
439
 * Generating a defuse key.
440
 *
441
 * @return string
442
 */
443
function defuse_generate_key()
444
{
445
    include_once '../includes/libraries/Encryption/Encryption/Crypto.php';
446
    include_once '../includes/libraries/Encryption/Encryption/Encoding.php';
447
    include_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
448
    include_once '../includes/libraries/Encryption/Encryption/Key.php';
449
    include_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
450
    include_once '../includes/libraries/Encryption/Encryption/File.php';
451
    include_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
452
    include_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
453
    include_once '../includes/libraries/Encryption/Encryption/Core.php';
454
455
    $key = \Defuse\Crypto\Key::createNewRandomKey();
456
    $key = $key->saveToAsciiSafeString();
457
458
    return $key;
459
}
460
461
/**
462
 * Generate a Defuse personal key.
463
 *
464
 * @param string $psk psk used
465
 *
466
 * @return string
467
 */
468
function defuse_generate_personal_key($psk)
469
{
470
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
471
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
472
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
473
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
474
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
475
    require_once '../includes/libraries/Encryption/Encryption/File.php';
476
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
477
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
478
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
479
480
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
481
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
482
483
    return $protected_key_encoded; // save this in user table
484
}
485
486
/**
487
 * Validate persoanl key with defuse.
488
 *
489
 * @param string $psk                   the user's psk
490
 * @param string $protected_key_encoded special key
491
 *
492
 * @return string
493
 */
494
function defuse_validate_personal_key($psk, $protected_key_encoded)
495
{
496
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
497
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
498
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
499
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
500
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
501
    require_once '../includes/libraries/Encryption/Encryption/File.php';
502
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
503
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
504
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
505
506
    try {
507
        $protected_key = \Defuse\Crypto\KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
508
        $user_key = $protected_key->unlockKey($psk);
509
        $user_key_encoded = $user_key->saveToAsciiSafeString();
510
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
511
        return 'Error - Major issue as the encryption is broken.';
512
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
513
        return 'Error - The saltkey is not the correct one.';
514
    }
515
516
    return $user_key_encoded; // store it in session once user has entered his psk
517
}
518
519
/**
520
 * Decrypt a defuse string if encrypted.
521
 *
522
 * @param string $value Encrypted string
523
 *
524
 * @return string Decrypted string
525
 */
526
function defuseReturnDecrypted($value, $SETTINGS)
527
{
528
    if (substr($value, 0, 3) === 'def') {
529
        $value = cryption($value, '', 'decrypt', $SETTINGS)['string'];
530
    }
531
532
    return $value;
533
}
534
535
/**
536
 * trimElement().
537
 *
538
 * trim a string depending on a specific string
539
 *
540
 * @param string $chaine  what to trim
541
 * @param string $element trim on what
542
 *
543
 * @return string
544
 */
545
function trimElement($chaine, $element)
546
{
547
    if (!empty($chaine)) {
548
        if (is_array($chaine) === true) {
0 ignored issues
show
introduced by
The condition is_array($chaine) === true is always false.
Loading history...
549
            $chaine = implode(';', $chaine);
550
        }
551
        $chaine = trim($chaine);
552
        if (substr($chaine, 0, 1) === $element) {
553
            $chaine = substr($chaine, 1);
554
        }
555
        if (substr($chaine, strlen($chaine) - 1, 1) === $element) {
556
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
557
        }
558
    }
559
560
    return $chaine;
561
}
562
563
/**
564
 * Permits to suppress all "special" characters from string.
565
 *
566
 * @param string $string  what to clean
567
 * @param bool   $special use of special chars?
568
 *
569
 * @return string
570
 */
571
function cleanString($string, $special = false)
572
{
573
    // Create temporary table for special characters escape
574
    $tabSpecialChar = array();
575
    for ($i = 0; $i <= 31; ++$i) {
576
        $tabSpecialChar[] = chr($i);
577
    }
578
    array_push($tabSpecialChar, '<br />');
579
    if ((int) $special === 1) {
580
        $tabSpecialChar = array_merge($tabSpecialChar, array('</li>', '<ul>', '<ol>'));
581
    }
582
583
    return str_replace($tabSpecialChar, "\n", $string);
584
}
585
586
/**
587
 * Erro manager for DB.
588
 *
589
 * @param array $params output from query
590
 */
591
function db_error_handler($params)
592
{
593
    echo 'Error: '.$params['error']."<br>\n";
594
    echo 'Query: '.$params['query']."<br>\n";
595
    throw new Exception('Error - Query', 1);
596
}
597
598
/**
599
 * [identifyUserRights description].
600
 *
601
 * @param string $groupesVisiblesUser  [description]
602
 * @param string $groupesInterditsUser [description]
603
 * @param string $isAdmin              [description]
604
 * @param string $idFonctions          [description]
605
 *
606
 * @return string [description]
607
 */
608
function identifyUserRights(
609
    $groupesVisiblesUser,
610
    $groupesInterditsUser,
611
    $isAdmin,
612
    $idFonctions,
613
    $SETTINGS
614
) {
615
    //load ClassLoader
616
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
617
618
    //Connect to DB
619
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
620
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
621
    $link->set_charset(DB_ENCODING);
622
623
    //Build tree
624
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
625
    $tree->register();
626
    $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
627
628
    // Check if user is ADMINISTRATOR
629
    if ($isAdmin === '1') {
630
        identAdmin(
631
            $idFonctions,
632
            $SETTINGS,
633
            $tree
634
        );
635
    } else {
636
        identUser(
637
            $groupesVisiblesUser,
638
            $groupesInterditsUser,
639
            $idFonctions,
640
            $SETTINGS,
641
            $tree
642
        );
643
    }
644
645
    // update user's timestamp
646
    DB::update(
647
        prefixTable('users'),
648
        array(
649
            'timestamp' => time(),
650
        ),
651
        'id=%i',
652
        $_SESSION['user_id']
653
    );
654
}
655
656
/**
657
 * Identify administrator.
658
 *
659
 * @param string     $idFonctions Roles of user
660
 * @param array      $SETTINGS    Teampass settings
661
 * @param mysqli     $link        DB connection
662
 * @param NestedTree $tree        Tree of folders
0 ignored issues
show
Bug introduced by
The type NestedTree was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
663
 */
664
function identAdmin($idFonctions, $SETTINGS, $tree)
665
{
666
    $groupesVisibles = array();
667
    $_SESSION['personal_folders'] = array();
668
    $_SESSION['groupes_visibles'] = array();
669
    $_SESSION['groupes_interdits'] = array();
670
    $_SESSION['personal_visible_groups'] = array();
671
    $_SESSION['read_only_folders'] = array();
672
    $_SESSION['list_restricted_folders_for_items'] = array();
673
    $_SESSION['list_folders_editable_by_role'] = array();
674
    $_SESSION['list_folders_limited'] = array();
675
    $_SESSION['no_access_folders'] = array();
676
    $_SESSION['groupes_visibles_list'] = '';
677
678
    // Get list of Folders
679
    $rows = DB::query('SELECT id FROM '.prefixTable('nested_tree').' WHERE personal_folder = %i', 0);
680
    foreach ($rows as $record) {
681
        array_push($groupesVisibles, $record['id']);
682
    }
683
    $_SESSION['groupes_visibles'] = $groupesVisibles;
684
    $_SESSION['all_non_personal_folders'] = $groupesVisibles;
685
    // Exclude all PF
686
    $_SESSION['forbiden_pfs'] = array();
687
    $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
688
    $where->add('personal_folder=%i', 1);
689
    if (isset($SETTINGS['enable_pf_feature']) === true
690
        && (int) $SETTINGS['enable_pf_feature'] === 1
691
    ) {
692
        $where->add('title=%s', $_SESSION['user_id']);
693
        $where->negateLast();
694
    }
695
    // Get ID of personal folder
696
    $persfld = DB::queryfirstrow(
697
        'SELECT id FROM '.prefixTable('nested_tree').' WHERE title = %s',
698
        $_SESSION['user_id']
699
    );
700
    if (empty($persfld['id']) === false) {
701
        if (in_array($persfld['id'], $_SESSION['groupes_visibles']) === false) {
702
            array_push($_SESSION['groupes_visibles'], $persfld['id']);
703
            array_push($_SESSION['personal_visible_groups'], $persfld['id']);
704
            // get all descendants
705
            $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
706
            $tree->rebuild();
707
            $tst = $tree->getDescendants($persfld['id']);
708
            foreach ($tst as $t) {
709
                array_push($_SESSION['groupes_visibles'], $t->id);
710
                array_push($_SESSION['personal_visible_groups'], $t->id);
711
            }
712
        }
713
    }
714
715
    // get complete list of ROLES
716
    $tmp = explode(';', $idFonctions);
717
    $rows = DB::query(
718
        'SELECT * FROM '.prefixTable('roles_title').'
719
        ORDER BY title ASC'
720
    );
721
    foreach ($rows as $record) {
722
        if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
723
            array_push($tmp, $record['id']);
724
        }
725
    }
726
    $_SESSION['fonction_id'] = implode(';', $tmp);
727
728
    $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
729
    $_SESSION['is_admin'] = 1;
730
    // Check if admin has created Folders and Roles
731
    DB::query('SELECT * FROM '.prefixTable('nested_tree').'');
732
    $_SESSION['nb_folders'] = DB::count();
733
    DB::query('SELECT * FROM '.prefixTable('roles_title'));
734
    $_SESSION['nb_roles'] = DB::count();
735
}
736
737
/**
738
 * Undocumented function.
739
 *
740
 * @param string     $groupesVisiblesUser  Allowed folders
741
 * @param string     $groupesInterditsUser Not allowed folders
742
 * @param string     $idFonctions          Roles of user
743
 * @param array      $SETTINGS             Teampass settings
744
 * @param mysqli     $link                 DB connection
745
 * @param NestedTree $tree                 Tree of folders
746
 */
747
function identUser(
748
    $groupesVisiblesUser,
749
    $groupesInterditsUser,
750
    $idFonctions,
751
    $SETTINGS,
752
    $tree
753
) {
754
    // init
755
    $_SESSION['groupes_visibles'] = array();
756
    $_SESSION['personal_folders'] = array();
757
    $_SESSION['groupes_interdits'] = array();
758
    $_SESSION['personal_visible_groups'] = array();
759
    $_SESSION['read_only_folders'] = array();
760
    $_SESSION['fonction_id'] = $idFonctions;
761
762
    $groupesInterdits = array();
763
    if (is_array($groupesInterditsUser) === false) {
0 ignored issues
show
introduced by
The condition is_array($groupesInterditsUser) === false is always true.
Loading history...
764
        $groupesInterditsUser = explode(';', trimElement(/* @scrutinizer ignore-type */ $groupesInterditsUser, ';'));
765
    }
766
    if (empty($groupesInterditsUser) === false && count($groupesInterditsUser) > 0) {
767
        $groupesInterdits = $groupesInterditsUser;
768
    }
769
    $_SESSION['is_admin'] = '0';
770
    $fonctionsAssociees = explode(';', trimElement($idFonctions, ';'));
771
772
    $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
773
774
    // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
775
    foreach ($fonctionsAssociees as $roleId) {
776
        if (empty($roleId) === false) {
777
            // Get allowed folders for each Role
778
            $rows = DB::query(
779
                'SELECT folder_id FROM '.prefixTable('roles_values').' WHERE role_id=%i',
780
                $roleId
781
            );
782
783
            if (DB::count() > 0) {
784
                $tmp = DB::queryfirstrow(
785
                    'SELECT allow_pw_change FROM '.prefixTable('roles_title').' WHERE id = %i',
786
                    $roleId
787
                );
788
                foreach ($rows as $record) {
789
                    if (isset($record['folder_id']) && in_array($record['folder_id'], $listAllowedFolders) === false) {
790
                        array_push($listAllowedFolders, $record['folder_id']);
791
                    }
792
                    // Check if this group is allowed to modify any pw in allowed folders
793
                    if ((int) $tmp['allow_pw_change'] === 1
794
                        && in_array($record['folder_id'], $listFoldersEditableByRole) === false
795
                    ) {
796
                        array_push($listFoldersEditableByRole, $record['folder_id']);
797
                    }
798
                }
799
                // Check for the users roles if some specific rights exist on items
800
                $rows = DB::query(
801
                    'SELECT i.id_tree, r.item_id
802
                    FROM '.prefixTable('items').' as i
803
                    INNER JOIN '.prefixTable('restriction_to_roles').' as r ON (r.item_id=i.id)
804
                    WHERE r.role_id=%i
805
                    ORDER BY i.id_tree ASC',
806
                    $roleId
807
                );
808
                $inc = 0;
809
                foreach ($rows as $record) {
810
                    if (isset($record['id_tree'])) {
811
                        $listFoldersLimited[$record['id_tree']][$inc] = $record['item_id'];
812
                        ++$inc;
813
                    }
814
                }
815
            }
816
        }
817
    }
818
819
    // Clean arrays
820
    $listAllowedFolders = array_unique($listAllowedFolders);
821
    $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ';'));
822
823
    // Does this user is allowed to see other items
824
    $inc = 0;
825
    $rows = DB::query(
826
        'SELECT id, id_tree FROM '.prefixTable('items').'
827
        WHERE restricted_to LIKE %ss AND inactif=%s',
828
        $_SESSION['user_id'].';',
829
        '0'
830
    );
831
    foreach ($rows as $record) {
832
        // Exclude restriction on item if folder is fully accessible
833
        if (in_array($record['id_tree'], $listAllowedFolders) === false) {
834
            $listRestrictedFoldersForItems[$record['id_tree']][$inc] = $record['id'];
835
            ++$inc;
836
        }
837
    }
838
839
    // => Build final lists
840
    // Add user allowed folders
841
    $allowedFoldersTmp = array_unique(
842
        array_merge($listAllowedFolders, $groupesVisiblesUser)
843
    );
844
    // Exclude from allowed folders all the specific user forbidden folders
845
    $allowedFolders = array();
846
    foreach ($allowedFoldersTmp as $ident) {
847
        if (!in_array($ident, $groupesInterditsUser) && !empty($ident)) {
848
            array_push($allowedFolders, $ident);
849
        }
850
    }
851
852
    // Clean array
853
    $listAllowedFolders = array_filter(array_unique($allowedFolders));
854
855
    // Exclude all PF
856
    $_SESSION['forbiden_pfs'] = array();
857
858
    $where = new WhereClause('and');
859
    $where->add('personal_folder=%i', 1);
860
    if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
861
        && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
862
    ) {
863
        $where->add('title=%s', $_SESSION['user_id']);
864
        $where->negateLast();
865
    }
866
867
    $persoFlds = DB::query(
868
        'SELECT id
869
        FROM '.prefixTable('nested_tree').'
870
        WHERE %l',
871
        $where
872
    );
873
    foreach ($persoFlds as $persoFldId) {
874
        array_push($_SESSION['forbiden_pfs'], $persoFldId['id']);
875
    }
876
    // Get IDs of personal folders
877
    if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
878
        && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
879
    ) {
880
        $persoFld = DB::queryfirstrow(
881
            'SELECT id
882
            FROM '.prefixTable('nested_tree').'
883
            WHERE title = %s AND personal_folder = %i',
884
            $_SESSION['user_id'],
885
            1
886
        );
887
        if (empty($persoFld['id']) === false) {
888
            if (in_array($persoFld['id'], $listAllowedFolders) === false) {
889
                array_push($_SESSION['personal_folders'], $persoFld['id']);
890
                array_push($listAllowedFolders, $persoFld['id']);
891
                array_push($_SESSION['personal_visible_groups'], $persoFld['id']);
892
                // get all descendants
893
                $ids = $tree->getChildren($persoFld['id'], false, false);
894
                foreach ($ids as $ident) {
895
                    if ($ident->personal_folder === 1) {
896
                        array_push($listAllowedFolders, $ident->id);
897
                        array_push($_SESSION['personal_visible_groups'], $ident->id);
898
                        array_push($_SESSION['personal_folders'], $ident->id);
899
                    }
900
                }
901
            }
902
        }
903
        // get list of readonly folders when pf is disabled.
904
        $_SESSION['personal_folders'] = array_unique($_SESSION['personal_folders']);
905
        // rule - if one folder is set as W or N in one of the Role, then User has access as W
906
        foreach ($listAllowedFolders as $folderId) {
907
            if (in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders']))) === false) {
908
                DB::query(
909
                    'SELECT *
910
                    FROM '.prefixTable('roles_values').'
911
                    WHERE folder_id = %i AND role_id IN %li AND type IN %ls',
912
                    $folderId,
913
                    $fonctionsAssociees,
914
                    array('W', 'ND', 'NE', 'NDNE')
915
                );
916
                if (DB::count() === 0 && in_array($folderId, $groupesVisiblesUser) === false) {
917
                    array_push($listReadOnlyFolders, $folderId);
918
                }
919
            }
920
        }
921
    } else {
922
        // get list of readonly folders when pf is disabled.
923
        // rule - if one folder is set as W in one of the Role, then User has access as W
924
        foreach ($listAllowedFolders as $folderId) {
925
            if (in_array($folderId, $listReadOnlyFolders) === false) {
926
                DB::query(
927
                    'SELECT *
928
                    FROM '.prefixTable('roles_values').'
929
                    WHERE folder_id = %i AND role_id IN %li AND type IN %ls',
930
                    $folderId,
931
                    $fonctionsAssociees,
932
                    array('W', 'ND', 'NE', 'NDNE')
933
                );
934
                if (DB::count() === 0 && in_array($folderId, $groupesVisiblesUser) === false) {
935
                    array_push($listReadOnlyFolders, $folderId);
936
                }
937
            }
938
        }
939
    }
940
941
    // check if change proposals on User's items
942
    if (isset($SETTINGS['enable_suggestion']) === true && $SETTINGS['enable_suggestion'] === '1') {
943
        DB::query(
944
            'SELECT *
945
            FROM '.prefixTable('items_change').' AS c
946
            LEFT JOIN '.prefixTable('log_items').' AS i ON (c.item_id = i.id_item)
947
            WHERE i.action = %s AND i.id_user = %i',
948
            'at_creation',
949
            $_SESSION['user_id']
950
        );
951
        $_SESSION['nb_item_change_proposals'] = DB::count();
952
    } else {
953
        $_SESSION['nb_item_change_proposals'] = 0;
954
    }
955
956
    $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
957
    $_SESSION['groupes_visibles'] = $listAllowedFolders;
958
    $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
959
    $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
960
    $_SESSION['read_only_folders'] = $listReadOnlyFolders;
961
    $_SESSION['no_access_folders'] = $groupesInterdits;
962
963
    $_SESSION['list_folders_limited'] = $listFoldersLimited;
964
    $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
965
    $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
966
    // Folders and Roles numbers
967
    DB::queryfirstrow('SELECT id FROM '.prefixTable('nested_tree').'');
968
    $_SESSION['nb_folders'] = DB::count();
969
    DB::queryfirstrow('SELECT id FROM '.prefixTable('roles_title'));
970
    $_SESSION['nb_roles'] = DB::count();
971
}
972
973
/**
974
 * Update the CACHE table
975
 *
976
 * @param string $action   What to do
977
 * @param array  $SETTINGS Teampass settings
978
 * @param string $ident    Ident format
979
 *
980
 * @return void
981
 */
982
function updateCacheTable($action, $SETTINGS, $ident = null)
983
{
984
    if ($action === 'reload') {
985
        // Rebuild full cache table
986
        cacheTableRefresh($SETTINGS);
987
    } elseif ($action === 'update_value' && is_null($ident) === false) {
988
        // UPDATE an item
989
        cacheTableUpdate($SETTINGS, $ident);
990
    } elseif ($action === 'add_value' && is_null($ident) === false) {
991
        // ADD an item
992
        cacheTableAdd($SETTINGS, $ident);
993
    } elseif ($action === 'delete_value' && is_null($ident) === false) {
994
        // DELETE an item
995
        DB::delete(prefixTable('cache'), 'id = %i', $ident);
996
    }
997
}
998
999
/**
1000
 * Cache table - refresh
1001
 *
1002
 * @param array  $SETTINGS Teampass settings
1003
 *
1004
 * @return void
1005
 */
1006
function cacheTableRefresh($SETTINGS)
1007
{
1008
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1009
1010
    //Connect to DB
1011
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1012
    DB::$host = DB_HOST;
1013
    DB::$user = DB_USER;
1014
    DB::$password = defuseReturnDecrypted(DB_PASSWD, $SETTINGS);
1015
    DB::$dbName = DB_NAME;
1016
    DB::$port = DB_PORT;
1017
    DB::$encoding = DB_ENCODING;
1018
1019
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
1020
    $link->set_charset(DB_ENCODING);
1021
1022
    //Load Tree
1023
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1024
    $tree->register();
1025
    $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
1026
1027
    // truncate table
1028
    DB::query('TRUNCATE TABLE '.prefixTable('cache'));
1029
1030
    // reload date
1031
    $rows = DB::query(
1032
        'SELECT *
1033
        FROM '.prefixTable('items').' as i
1034
        INNER JOIN '.prefixTable('log_items').' as l ON (l.id_item = i.id)
1035
        AND l.action = %s
1036
        AND i.inactif = %i',
1037
        'at_creation',
1038
        0
1039
    );
1040
    foreach ($rows as $record) {
1041
        if (empty($record['id_tree']) === false) {
1042
            // Get all TAGS
1043
            $tags = '';
1044
            $itemTags = DB::query('SELECT tag FROM '.prefixTable('tags').' WHERE item_id=%i', $record['id']);
1045
            foreach ($itemTags as $itemTag) {
1046
                if (!empty($itemTag['tag'])) {
1047
                    $tags .= $itemTag['tag'].' ';
1048
                }
1049
            }
1050
            // Get renewal period
1051
            $resNT = DB::queryfirstrow('SELECT renewal_period FROM '.prefixTable('nested_tree').' WHERE id=%i', $record['id_tree']);
1052
1053
            // form id_tree to full foldername
1054
            $folder = '';
1055
            $arbo = $tree->getPath($record['id_tree'], true);
1056
            foreach ($arbo as $elem) {
1057
                if ((int) $elem->title === $_SESSION['user_id']
1058
                    && (int) $elem->nlevel === 1
1059
                ) {
1060
                    $elem->title = $_SESSION['login'];
1061
                }
1062
                if (empty($folder)) {
1063
                    $folder = stripslashes($elem->title);
1064
                } else {
1065
                    $folder .= ' » '.stripslashes($elem->title);
1066
                }
1067
            }
1068
            // store data
1069
            DB::insert(
1070
                prefixTable('cache'),
1071
                array(
1072
                    'id' => $record['id'],
1073
                    'label' => $record['label'],
1074
                    'description' => isset($record['description']) ? $record['description'] : '',
1075
                    'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : '0',
1076
                    'tags' => $tags,
1077
                    'id_tree' => $record['id_tree'],
1078
                    'perso' => $record['perso'],
1079
                    'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : '0',
1080
                    'login' => isset($record['login']) ? $record['login'] : '',
1081
                    'folder' => $folder,
1082
                    'author' => $record['id_user'],
1083
                    'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : '0',
1084
                    'timestamp' => $record['date'],
1085
                )
1086
            );
1087
        }
1088
    }
1089
}
1090
1091
/**
1092
 * Cache table - update existing value
1093
 *
1094
 * @param array  $SETTINGS Teampass settings
1095
 * @param string $ident    Ident format
1096
 *
1097
 * @return void
1098
 */
1099
function cacheTableUpdate($action, $SETTINGS, $ident = null)
1100
{
1101
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1102
1103
    //Connect to DB
1104
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1105
    DB::$host = DB_HOST;
1106
    DB::$user = DB_USER;
1107
    DB::$password = defuseReturnDecrypted(DB_PASSWD, $SETTINGS);
1108
    DB::$dbName = DB_NAME;
1109
    DB::$port = DB_PORT;
1110
    DB::$encoding = DB_ENCODING;
1111
1112
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
1113
    $link->set_charset(DB_ENCODING);
1114
1115
    //Load Tree
1116
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1117
    $tree->register();
1118
    $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
1119
1120
    // get new value from db
1121
    $data = DB::queryfirstrow(
1122
        'SELECT label, description, id_tree, perso, restricted_to, login, url
1123
        FROM '.prefixTable('items').'
1124
        WHERE id=%i',
1125
        $ident
1126
    );
1127
    // Get all TAGS
1128
    $tags = '';
1129
    $itemTags = DB::query('SELECT tag FROM '.prefixTable('tags').' WHERE item_id=%i', $ident);
1130
    foreach ($itemTags as $itemTag) {
1131
        if (!empty($itemTag['tag'])) {
1132
            $tags .= $itemTag['tag'].' ';
1133
        }
1134
    }
1135
    // form id_tree to full foldername
1136
    $folder = '';
1137
    $arbo = $tree->getPath($data['id_tree'], true);
1138
    foreach ($arbo as $elem) {
1139
        if ((int) $elem->title === $_SESSION['user_id'] && (int) $elem->nlevel === 1) {
1140
            $elem->title = $_SESSION['login'];
1141
        }
1142
        if (empty($folder)) {
1143
            $folder = stripslashes($elem->title);
1144
        } else {
1145
            $folder .= ' » '.stripslashes($elem->title);
1146
        }
1147
    }
1148
    // finaly update
1149
    DB::update(
1150
        prefixTable('cache'),
1151
        array(
1152
            'label' => $data['label'],
1153
            'description' => $data['description'],
1154
            'tags' => $tags,
1155
            'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : '0',
1156
            'id_tree' => $data['id_tree'],
1157
            'perso' => $data['perso'],
1158
            'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : '0',
1159
            'login' => isset($data['login']) ? $data['login'] : '',
1160
            'folder' => $folder,
1161
            'author' => $_SESSION['user_id'],
1162
            ),
1163
        'id = %i',
1164
        $ident
1165
    );
1166
}
1167
1168
/**
1169
 * Cache table - add new value
1170
 *
1171
 * @param array  $SETTINGS Teampass settings
1172
 * @param string $ident    Ident format
1173
 *
1174
 * @return void
1175
 */
1176
function cacheTableAdd($action, $SETTINGS, $ident = null)
1177
{
1178
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1179
1180
    //Connect to DB
1181
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1182
    DB::$host = DB_HOST;
1183
    DB::$user = DB_USER;
1184
    DB::$password = defuseReturnDecrypted(DB_PASSWD, $SETTINGS);
1185
    DB::$dbName = DB_NAME;
1186
    DB::$port = DB_PORT;
1187
    DB::$encoding = DB_ENCODING;
1188
1189
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
1190
    $link->set_charset(DB_ENCODING);
1191
1192
    //Load Tree
1193
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
1194
    $tree->register();
1195
    $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
1196
1197
    // get new value from db
1198
    $data = DB::queryFirstRow(
1199
        'SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
1200
        FROM '.prefixTable('items').' as i
1201
        INNER JOIN '.prefixTable('log_items').' as l ON (l.id_item = i.id)
1202
        WHERE i.id = %i
1203
        AND l.action = %s',
1204
        $ident,
1205
        'at_creation'
1206
    );
1207
    // Get all TAGS
1208
    $tags = '';
1209
    $itemTags = DB::query('SELECT tag FROM '.prefixTable('tags').' WHERE item_id = %i', $ident);
1210
    foreach ($itemTags as $itemTag) {
1211
        if (!empty($itemTag['tag'])) {
1212
            $tags .= $itemTag['tag'].' ';
1213
        }
1214
    }
1215
    // form id_tree to full foldername
1216
    $folder = '';
1217
    $arbo = $tree->getPath($data['id_tree'], true);
1218
    foreach ($arbo as $elem) {
1219
        if ((int) $elem->title === $_SESSION['user_id'] && (int) $elem->nlevel === 1) {
1220
            $elem->title = $_SESSION['login'];
1221
        }
1222
        if (empty($folder)) {
1223
            $folder = stripslashes($elem->title);
1224
        } else {
1225
            $folder .= ' » '.stripslashes($elem->title);
1226
        }
1227
    }
1228
    // finaly update
1229
    DB::insert(
1230
        prefixTable('cache'),
1231
        array(
1232
            'id' => $data['id'],
1233
            'label' => $data['label'],
1234
            'description' => $data['description'],
1235
            'tags' => (isset($tags) && !empty($tags)) ? $tags : 'None',
1236
            'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : '0',
1237
            'id_tree' => $data['id_tree'],
1238
            'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== 'None') ? $data['perso'] : '0',
1239
            'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : '0',
1240
            'login' => isset($data['login']) ? $data['login'] : '',
1241
            'folder' => $folder,
1242
            'author' => $_SESSION['user_id'],
1243
            'timestamp' => $data['date'],
1244
        )
1245
    );
1246
}
1247
1248
1249
/**
1250
 * Do statistics
1251
 *
1252
 * @return array
1253
 */
1254
function getStatisticsData()
1255
{
1256
    DB::query(
1257
        'SELECT id FROM '.prefixTable('nested_tree').' WHERE personal_folder = %i',
1258
        0
1259
    );
1260
    $counter_folders = DB::count();
1261
1262
    DB::query(
1263
        'SELECT id FROM '.prefixTable('nested_tree').' WHERE personal_folder = %i',
1264
        1
1265
    );
1266
    $counter_folders_perso = DB::count();
1267
1268
    DB::query(
1269
        'SELECT id FROM '.prefixTable('items').' WHERE perso = %i',
1270
        0
1271
    );
1272
    $counter_items = DB::count();
1273
1274
    DB::query(
1275
        'SELECT id FROM '.prefixTable('items').' WHERE perso = %i',
1276
        1
1277
    );
1278
    $counter_items_perso = DB::count();
1279
1280
    DB::query(
1281
        'SELECT id FROM '.prefixTable('users').''
1282
    );
1283
    $counter_users = DB::count();
1284
1285
    DB::query(
1286
        'SELECT id FROM '.prefixTable('users').' WHERE admin = %i',
1287
        1
1288
    );
1289
    $admins = DB::count();
1290
1291
    DB::query(
1292
        'SELECT id FROM '.prefixTable('users').' WHERE gestionnaire = %i',
1293
        1
1294
    );
1295
    $managers = DB::count();
1296
1297
    DB::query(
1298
        'SELECT id FROM '.prefixTable('users').' WHERE read_only = %i',
1299
        1
1300
    );
1301
    $readOnly = DB::count();
1302
1303
    // list the languages
1304
    $usedLang = [];
1305
    $tp_languages = DB::query(
1306
        'SELECT name FROM '.prefixTable('languages')
1307
    );
1308
    foreach ($tp_languages as $tp_language) {
1309
        DB::query(
1310
            'SELECT * FROM '.prefixTable('users').' WHERE user_language = %s',
1311
            $tp_language['name']
1312
        );
1313
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1314
    }
1315
1316
    // get list of ips
1317
    $usedIp = [];
1318
    $tp_ips = DB::query(
1319
        'SELECT user_ip FROM '.prefixTable('users')
1320
    );
1321
    foreach ($tp_ips as $ip) {
1322
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1323
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1324
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== 'none') {
1325
            $usedIp[$ip['user_ip']] = 1;
1326
        }
1327
    }
1328
1329
    return array(
1330
        'error' => '',
1331
        'stat_phpversion' => phpversion(),
1332
        'stat_folders' => $counter_folders,
1333
        'stat_folders_shared' => intval($counter_folders) - intval($counter_folders_perso),
1334
        'stat_items' => $counter_items,
1335
        'stat_items_shared' => intval($counter_items) - intval($counter_items_perso),
1336
        'stat_users' => $counter_users,
1337
        'stat_admins' => $admins,
1338
        'stat_managers' => $managers,
1339
        'stat_ro' => $readOnly,
1340
        'stat_kb' => $SETTINGS['enable_kb'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $SETTINGS seems to be never defined.
Loading history...
1341
        'stat_pf' => $SETTINGS['enable_pf_feature'],
1342
        'stat_fav' => $SETTINGS['enable_favourites'],
1343
        'stat_teampassversion' => $SETTINGS['cpassman_version'],
1344
        'stat_ldap' => $SETTINGS['ldap_mode'],
1345
        'stat_agses' => $SETTINGS['agses_authentication_enabled'],
1346
        'stat_duo' => $SETTINGS['duo'],
1347
        'stat_suggestion' => $SETTINGS['enable_suggestion'],
1348
        'stat_api' => $SETTINGS['api'],
1349
        'stat_customfields' => $SETTINGS['item_extra_fields'],
1350
        'stat_syslog' => $SETTINGS['syslog_enable'],
1351
        'stat_2fa' => $SETTINGS['google_authentication'],
1352
        'stat_stricthttps' => $SETTINGS['enable_sts'],
1353
        'stat_mysqlversion' => DB::serverVersion(),
1354
        'stat_languages' => $usedLang,
1355
        'stat_country' => $usedIp,
1356
    );
1357
}
1358
1359
/**
1360
 * Permits to send an email.
1361
 *
1362
 * @param string $subject     email subject
1363
 * @param string $textMail    email message
1364
 * @param string $email       email
1365
 * @param array  $SETTINGS    settings
1366
 * @param string $textMailAlt email message alt
1367
 *
1368
 * @return string some json info
1369
 */
1370
function sendEmail(
1371
    $subject,
1372
    $textMail,
1373
    $email,
1374
    $SETTINGS,
1375
    $textMailAlt = null
1376
) {
1377
    // CAse where email not defined
1378
    if ($email === 'none') {
1379
        return '"error":"" , "message":"'.langHdl('forgot_my_pw_email_sent').'"';
1380
    }
1381
1382
    // Load settings
1383
    include_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
1384
1385
    // Load superglobal
1386
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1387
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
1388
1389
    // Get user language
1390
    $session_user_language = $superGlobal->get('user_language', 'SESSION');
1391
    $user_language = isset($session_user_language) ? $session_user_language : 'english';
1392
    include_once $SETTINGS['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1393
1394
    // Load library
1395
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1396
1397
    // load PHPMailer
1398
    $mail = new SplClassLoader('Email\PHPMailer', '../includes/libraries');
1399
    $mail->register();
1400
    $mail = new Email\PHPMailer\PHPMailer(true);
1401
1402
    // send to user
1403
    $mail->setLanguage('en', $SETTINGS['cpassman_dir'].'/includes/libraries/Email/PHPMailer/language/');
1404
    $mail->SMTPDebug = 0; //value 1 can be used to debug - 4 for debuging connections
1405
    $mail->Port = $SETTINGS['email_port']; //COULD BE USED
1406
    $mail->CharSet = 'utf-8';
1407
    $mail->SMTPSecure = ($SETTINGS['email_security'] === 'tls'
1408
    || $SETTINGS['email_security'] === 'ssl') ? $SETTINGS['email_security'] : '';
1409
    $mail->SMTPAutoTLS = ($SETTINGS['email_security'] === 'tls'
1410
        || $SETTINGS['email_security'] === 'ssl') ? true : false;
1411
    $mail->isSmtp(); // send via SMTP
1412
    $mail->Host = $SETTINGS['email_smtp_server']; // SMTP servers
1413
    $mail->SMTPAuth = (int) $SETTINGS['email_smtp_auth'] === 1 ? true : false; // turn on SMTP authentication
1414
    $mail->Username = $SETTINGS['email_auth_username']; // SMTP username
1415
    $mail->Password = $SETTINGS['email_auth_pwd']; // SMTP password
1416
    $mail->From = $SETTINGS['email_from'];
1417
    $mail->FromName = $SETTINGS['email_from_name'];
1418
1419
    // Prepare for each person
1420
    foreach (array_filter(explode(',', $email)) as $dest) {
1421
        $mail->addAddress($dest);
1422
    }
1423
1424
    // Prepare HTML
1425
    $text_html = emailBody($textMail);
1426
1427
    $mail->WordWrap = 80; // set word wrap
1428
    $mail->isHtml(true); // send as HTML
1429
    $mail->Subject = $subject;
1430
    $mail->Body = $text_html;
1431
    $mail->AltBody = (is_null($textMailAlt) === false) ? $textMailAlt : '';
1432
1433
    // send email
1434
    if ($mail->send()) {
1435
        return json_encode(
1436
            array(
1437
                'error' => '',
1438
                'message' => langHdl('forgot_my_pw_email_sent'),
1439
            )
1440
        );
1441
    } else {
1442
        return json_encode(
1443
            array(
1444
                'error' => 'error_mail_not_send',
1445
                'message' => str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo),
1446
            )
1447
        );
1448
    }
1449
}
1450
1451
/**
1452
 * Returns the email body
1453
 *
1454
 * @param string $textMail Text for the email
1455
 *
1456
 * @return string
1457
 */
1458
function emailBody($textMail)
1459
{
1460
    return '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.=
1461
    w3.org/TR/html4/loose.dtd"><html>
1462
    <head><title>Email Template</title>
1463
    <style type="text/css">
1464
    body { background-color: #f0f0f0; padding: 10px 0; margin:0 0 10px =0; }
1465
    </style></head>
1466
    <body style="-ms-text-size-adjust: none; size-adjust: none; margin: 0; padding: 10px 0; background-color: #f0f0f0;" bgcolor="#f0f0f0" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
1467
    <table border="0" width="100%" height="100%" cellpadding="0" cellspacing="0" bgcolor="#f0f0f0" style="border-spacing: 0;">
1468
    <tr><td style="border-collapse: collapse;"><br>
1469
        <table border="0" width="100%" cellpadding="0" cellspacing="0" bgcolor="#17357c" style="border-spacing: 0; margin-bottom: 25px;">
1470
        <tr><td style="border-collapse: collapse; padding: 11px 20px;">
1471
            <div style="max-width:150px; max-height:34px; color:#f0f0f0; font-weight:bold;">Teampass</div>
1472
        </td></tr></table></td>
1473
    </tr>
1474
    <tr><td align="center" valign="top" bgcolor="#f0f0f0" style="border-collapse: collapse; background-color: #f0f0f0;">
1475
        <table width="600" cellpadding="0" cellspacing="0" border="0" class="container" bgcolor="#ffffff" style="border-spacing: 0; border-bottom: 1px solid #e0e0e0; box-shadow: 0 0 3px #ddd; color: #434343; font-family: Helvetica, Verdana, sans-serif;">
1476
        <tr><td class="container-padding" bgcolor="#ffffff" style="border-collapse: collapse; border-left: 1px solid #e0e0e0; background-color: #ffffff; padding-left: 30px; padding-right: 30px;">
1477
        <br><div style="float:right;">'.
1478
    $textMail.
1479
    '<br><br></td></tr></table>
1480
    </td></tr></table>
1481
    <br></body></html>';
1482
}
1483
1484
/**
1485
 * Generate a Key.
1486
 *
1487
 * @return string
1488
 */
1489
function generateKey()
1490
{
1491
    return substr(md5(rand().rand()), 0, 15);
1492
}
1493
1494
/**
1495
 * Convert date to timestamp.
1496
 *
1497
 * @param string $date     The date
1498
 * @param array  $SETTINGS Teampass settings
1499
 *
1500
 * @return string
1501
 */
1502
function dateToStamp($date, $SETTINGS)
1503
{
1504
    $date = date_parse_from_format($SETTINGS['date_format'], $date);
1505
    if ((int) $date['warning_count'] === 0 && (int) $date['error_count'] === 0) {
1506
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1507
    } else {
1508
        return '';
1509
    }
1510
}
1511
1512
/**
1513
 * Is this a date.
1514
 *
1515
 * @param string $date Date
1516
 *
1517
 * @return bool
1518
 */
1519
function isDate($date)
1520
{
1521
    return strtotime($date) !== false;
1522
}
1523
1524
/**
1525
 * isUTF8().
1526
 *
1527
 * @return int is the string in UTF8 format
1528
 */
1529
function isUTF8($string)
1530
{
1531
    if (is_array($string) === true) {
1532
        $string = $string['string'];
1533
    }
1534
1535
    return preg_match(
1536
        '%^(?:
1537
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1538
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1539
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1540
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1541
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1542
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1543
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1544
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1545
        )*$%xs',
1546
        $string
1547
    );
1548
}
1549
1550
/**
1551
 * Prepare an array to UTF8 format before JSON_encode.
1552
 *
1553
 * @param array $array Array of values
1554
 *
1555
 * @return array
1556
 */
1557
function utf8Converter($array)
1558
{
1559
    array_walk_recursive(
1560
        $array,
1561
        function (&$item, $key) {
1562
            if (mb_detect_encoding($item, 'utf-8', true) === false) {
1563
                $item = utf8_encode($item);
1564
            }
1565
        }
1566
    );
1567
1568
    return $array;
1569
}
1570
1571
/**
1572
 * Permits to prepare data to be exchanged.
1573
 *
1574
 * @param array  $data Text
1575
 * @param string $type Parameter
1576
 *
1577
 * @return string
1578
 */
1579
function prepareExchangedData($data, $type, $key = null)
1580
{
1581
    if (isset($SETTINGS['cpassman_dir']) === false || empty($SETTINGS['cpassman_dir'])) {
1 ignored issue
show
Comprehensibility Best Practice introduced by
The variable $SETTINGS seems to never exist and therefore isset should always be false.
Loading history...
1582
        if (file_exists('../includes/config/tp.config.php')) {
1583
            include '../includes/config/tp.config.php';
1584
        } elseif (file_exists('./includes/config/tp.config.php')) {
1585
            include './includes/config/tp.config.php';
1586
        } elseif (file_exists('../../includes/config/tp.config.php')) {
1587
            include '../../includes/config/tp.config.php';
1588
        } else {
1589
            throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
1590
        }
1591
    }
1592
1593
    //load ClassLoader
1594
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1595
    //Load AES
1596
    $aes = new SplClassLoader('Encryption\Crypt', $SETTINGS['cpassman_dir'].'/includes/libraries');
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $SETTINGS seems to be never defined.
Loading history...
1597
    $aes->register();
1598
1599
    if ($key !== null) {
1600
        $_SESSION['key'] = $key;
1601
    }
1602
1603
    if ($type === 'encode') {
1604
        // Ensure UTF8 format
1605
        $data = utf8Converter($data);
1606
        // Now encode
1607
        if (isset($SETTINGS['encryptClientServer'])
1608
            && $SETTINGS['encryptClientServer'] === '0'
1609
        ) {
1610
            return json_encode(
1611
                $data,
1612
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1613
            );
1614
        } else {
1615
            return Encryption\Crypt\aesctr::encrypt(
1616
                json_encode(
1617
                    $data,
1618
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1619
                ),
1620
                $_SESSION['key'],
1621
                256
1622
            );
1623
        }
1624
    } elseif ($type === 'decode') {
1625
        if (isset($SETTINGS['encryptClientServer'])
1626
            && $SETTINGS['encryptClientServer'] === '0'
1627
        ) {
1628
            return json_decode(
1629
                $data,
0 ignored issues
show
Bug introduced by
$data of type array is incompatible with the type string expected by parameter $json of json_decode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1629
                /** @scrutinizer ignore-type */ $data,
Loading history...
1630
                true
1631
            );
1632
        } else {
1633
            return json_decode(
1634
                Encryption\Crypt\aesctr::decrypt(
1635
                    $data,
0 ignored issues
show
Bug introduced by
$data of type array is incompatible with the type Encryption\Crypt\source expected by parameter $ciphertext of Encryption\Crypt\aesctr::decrypt(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1635
                    /** @scrutinizer ignore-type */ $data,
Loading history...
1636
                    $_SESSION['key'],
1637
                    256
1638
                ),
1639
                true
1640
            );
1641
        }
1642
    }
1643
}
1644
1645
/**
1646
 * Create a thumbnail.
1647
 *
1648
 * @param string $src           Source
1649
 * @param string $dest          Destination
1650
 * @param int    $desired_width Size of width
1651
 */
1652
function makeThumbnail($src, $dest, $desired_width)
1653
{
1654
    /* read the source image */
1655
    $source_image = imagecreatefrompng($src);
1656
    $width = imagesx($source_image);
1657
    $height = imagesy($source_image);
1658
1659
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1660
    $desired_height = floor($height * ($desired_width / $width));
1661
1662
    /* create a new, "virtual" image */
1663
    $virtual_image = imagecreatetruecolor($desired_width, $desired_height);
0 ignored issues
show
Bug introduced by
$desired_height of type double is incompatible with the type integer expected by parameter $height of imagecreatetruecolor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1663
    $virtual_image = imagecreatetruecolor($desired_width, /** @scrutinizer ignore-type */ $desired_height);
Loading history...
1664
1665
    /* copy source image at a resized size */
1666
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
0 ignored issues
show
Bug introduced by
$desired_height of type double is incompatible with the type integer expected by parameter $dst_h of imagecopyresampled(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1666
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, /** @scrutinizer ignore-type */ $desired_height, $width, $height);
Loading history...
1667
1668
    /* create the physical thumbnail image to its destination */
1669
    imagejpeg($virtual_image, $dest);
1670
}
1671
1672
/**
1673
 * Check table prefix in SQL query.
1674
 *
1675
 * @param string $table Table name
1676
 *
1677
 * @return string
1678
 */
1679
function prefixTable($table)
1680
{
1681
    $safeTable = htmlspecialchars(DB_PREFIX.$table);
1682
    if (!empty($safeTable)) {
1683
        // sanitize string
1684
        return $safeTable;
1685
    } else {
1686
        // stop error no table
1687
        return 'table_not_exists';
1688
    }
1689
}
1690
1691
/*
1692
 * Creates a KEY using PasswordLib
1693
 */
1694
function GenerateCryptKey($size = null, $secure = false, $numerals = false, $capitalize = false, $symbols = false)
1695
{
1696
    global $SETTINGS;
1697
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1698
1699
    if ($secure === true) {
1700
        $numerals = true;
1701
        $capitalize = true;
1702
        $symbols = true;
1703
    }
1704
1705
    // Load libraries
1706
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
1707
    $generator->register();
1708
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
1709
1710
    // Can we use PHP7 random_int function?
1711
    if (version_compare(phpversion(), '7.0', '>=')) {
1712
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/PasswordGenerator/RandomGenerator/Php7RandomGenerator.php';
1713
        $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
1714
    }
1715
1716
    // init
1717
    if (empty($size) === false && is_null($size) === false) {
1718
        $generator->setLength(intval($size));
1719
    }
1720
    if (empty($numerals) === false) {
1721
        $generator->setNumbers($numerals);
1722
    }
1723
    if (empty($capitalize) === false) {
1724
        $generator->setUppercase($capitalize);
1725
    }
1726
    if (empty($symbols) === false) {
1727
        $generator->setSymbols($symbols);
1728
    }
1729
1730
    // generate and send back
1731
    return $generator->generatePassword();
1732
}
1733
1734
/*
1735
* Send sysLOG message
1736
* @param string $message
1737
* @param string $host
1738
*/
1739
function send_syslog($message, $host, $port, $component = 'teampass')
1740
{
1741
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1742
    $syslog_message = '<123>'.date('M d H:i:s ').$component.': '.$message;
1743
    socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1744
    socket_close($sock);
1745
}
1746
1747
/**
1748
 * logEvents().
1749
 *
1750
 * permits to log events into DB
1751
 *
1752
 * @param string $type
1753
 * @param string $label
1754
 * @param string $field_1
1755
 */
1756
function logEvents($type, $label, $who, $login = null, $field_1 = null)
1757
{
1758
    global $server, $user, $pass, $database, $port, $encoding;
1759
    global $SETTINGS;
1760
1761
    if (empty($who)) {
1762
        $who = getClientIpServer();
1763
    }
1764
1765
    // include librairies & connect to DB
1766
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1767
    DB::$host = DB_HOST;
1768
    DB::$user = DB_USER;
1769
    DB::$password = defuseReturnDecrypted(DB_PASSWD, $SETTINGS);
1770
    DB::$dbName = DB_NAME;
1771
    DB::$port = DB_PORT;
1772
    DB::$encoding = DB_ENCODING;
1773
    //DB::$errorHandler = true;
1774
1775
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
1776
    $link->set_charset(DB_ENCODING);
1777
1778
    DB::insert(
1779
        prefixTable('log_system'),
1780
        array(
1781
            'type' => $type,
1782
            'date' => time(),
1783
            'label' => $label,
1784
            'qui' => $who,
1785
            'field_1' => $field_1 === null ? '' : $field_1,
1786
        )
1787
    );
1788
1789
    // If SYSLOG
1790
    if (isset($SETTINGS['syslog_enable']) === true && (int) $SETTINGS['syslog_enable'] === 1) {
1791
        if ($type === 'user_mngt') {
1792
            send_syslog(
1793
                'action='.str_replace('at_', '', $label).' attribute=user user='.$who.' userid="'.$login.'" change="'.$field_1.'" ',
1794
                $SETTINGS['syslog_host'],
1795
                $SETTINGS['syslog_port'],
1796
                'teampass'
1797
            );
1798
        } else {
1799
            send_syslog(
1800
                'action='.$type.' attribute='.$label.' user='.$who.' userid="'.$login.'" ',
1801
                $SETTINGS['syslog_host'],
1802
                $SETTINGS['syslog_port'],
1803
                'teampass'
1804
            );
1805
        }
1806
    }
1807
}
1808
1809
/**
1810
 * Log events.
1811
 *
1812
 * @param array  $SETTINGS        Teampass settings
1813
 * @param int    $item_id         Item id
1814
 * @param string $item_label      Item label
1815
 * @param int    $id_user         User id
1816
 * @param string $action          Code for reason
1817
 * @param string $login           User login
1818
 * @param string $raison          Code for reason
1819
 * @param string $encryption_type Encryption on
1820
 */
1821
function logItems(
1822
    $SETTINGS,
1823
    $item_id,
1824
    $item_label,
1825
    $id_user,
1826
    $action,
1827
    $login = null,
1828
    $raison = null,
1829
    $encryption_type = null
1830
) {
1831
    $dataItem = '';
1832
1833
    // include librairies & connect to DB
1834
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1835
    DB::$host = DB_HOST;
1836
    DB::$user = DB_USER;
1837
    DB::$password = defuseReturnDecrypted(DB_PASSWD, $SETTINGS);
1838
    DB::$dbName = DB_NAME;
1839
    DB::$port = DB_PORT;
1840
    DB::$encoding = DB_ENCODING;
1841
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
1842
    $link->set_charset(DB_ENCODING);
1843
1844
    // Insert log in DB
1845
    DB::insert(
1846
        prefixTable('log_items'),
1847
        array(
1848
            'id_item' => $item_id,
1849
            'date' => time(),
1850
            'id_user' => $id_user,
1851
            'action' => $action,
1852
            'raison' => $raison,
1853
            'raison_iv' => '',
1854
            'encryption_type' => is_null($encryption_type) === true ? '' : $encryption_type,
1855
        )
1856
    );
1857
    // Timestamp the last change
1858
    if ($action === 'at_creation' || $action === 'at_modifiation' || $action === 'at_delete' || $action === 'at_import') {
1859
        DB::update(
1860
            prefixTable('misc'),
1861
            array(
1862
                'valeur' => time(),
1863
                ),
1864
            'type = %s AND intitule = %s',
1865
            'timestamp',
1866
            'last_item_change'
1867
        );
1868
    }
1869
1870
    // SYSLOG
1871
    if (isset($SETTINGS['syslog_enable']) === true && $SETTINGS['syslog_enable'] === '1') {
1872
        // Extract reason
1873
        $attribute = explode(' : ', $raison);
1874
1875
        // Get item info if not known
1876
        if (empty($item_label) === true) {
1877
            $dataItem = DB::queryfirstrow(
1878
                'SELECT id, id_tree, label
1879
                FROM '.prefixTable('items').'
1880
                WHERE id = %i',
1881
                $item_id
1882
            );
1883
1884
            $item_label = $dataItem['label'];
1885
        }
1886
1887
        send_syslog(
1888
            'action='.str_replace('at_', '', $action).' attribute='.str_replace('at_', '', $attribute[0]).' itemno='.$item_id.' user='.addslashes($login).' itemname="'.addslashes($item_label).'"',
1889
            $SETTINGS['syslog_host'],
1890
            $SETTINGS['syslog_port'],
1891
            'teampass'
1892
        );
1893
    }
1894
1895
    // send notification if enabled
1896
    if (isset($SETTINGS['enable_email_notification_on_item_shown']) === true
1897
        && $SETTINGS['enable_email_notification_on_item_shown'] === '1'
1898
        && $action === 'at_shown'
1899
    ) {
1900
        // Get info about item
1901
        if (empty($dataItem) === true || empty($item_label) === true) {
1902
            $dataItem = DB::queryfirstrow(
1903
                'SELECT id, id_tree, label
1904
                FROM '.prefixTable('items').'
1905
                WHERE id = %i',
1906
                $item_id
1907
            );
1908
            $item_label = $dataItem['label'];
1909
        }
1910
1911
        // send back infos
1912
        DB::insert(
1913
            prefixTable('emails'),
1914
            array(
1915
                'timestamp' => time(),
1916
                'subject' => langHdl('email_on_open_notification_subject'),
1917
                'body' => str_replace(
1918
                    array('#tp_user#', '#tp_item#', '#tp_link#'),
1919
                    array(
1920
                        addslashes($_SESSION['login']),
1921
                        addslashes($item_label),
1922
                        $SETTINGS['cpassman_url'].'/index.php?page=items&group='.$dataItem['id_tree'].'&id='.$dataItem['id'],
1923
                    ),
1924
                    langHdl('email_on_open_notification_mail')
1925
                ),
1926
                'receivers' => $_SESSION['listNotificationEmails'],
1927
                'status' => '',
1928
            )
1929
        );
1930
    }
1931
}
1932
1933
/**
1934
 * Get the client ip address.
1935
 *
1936
 * @return string IP address
1937
 */
1938
function getClientIpServer()
1939
{
1940
    if (getenv('HTTP_CLIENT_IP')) {
1941
        $ipaddress = getenv('HTTP_CLIENT_IP');
1942
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1943
        $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1944
    } elseif (getenv('HTTP_X_FORWARDED')) {
1945
        $ipaddress = getenv('HTTP_X_FORWARDED');
1946
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1947
        $ipaddress = getenv('HTTP_FORWARDED_FOR');
1948
    } elseif (getenv('HTTP_FORWARDED')) {
1949
        $ipaddress = getenv('HTTP_FORWARDED');
1950
    } elseif (getenv('REMOTE_ADDR')) {
1951
        $ipaddress = getenv('REMOTE_ADDR');
1952
    } else {
1953
        $ipaddress = 'UNKNOWN';
1954
    }
1955
1956
    return $ipaddress;
1957
}
1958
1959
/**
1960
 * Escape all HTML, JavaScript, and CSS.
1961
 *
1962
 * @param string $input    The input string
1963
 * @param string $encoding Which character encoding are we using?
1964
 *
1965
 * @return string
1966
 */
1967
function noHTML($input, $encoding = 'UTF-8')
1968
{
1969
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1970
}
1971
1972
/**
1973
 * handleConfigFile().
1974
 *
1975
 * permits to handle the Teampass config file
1976
 * $action accepts "rebuild" and "update"
1977
 */
1978
function handleConfigFile($action, $field = null, $value = null)
1979
{
1980
    global $server, $user, $pass, $database, $port, $encoding;
1981
    global $SETTINGS;
1982
1983
    $tp_config_file = '../includes/config/tp.config.php';
1984
1985
    // include librairies & connect to DB
1986
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1987
    DB::$host = DB_HOST;
1988
    DB::$user = DB_USER;
1989
    DB::$password = defuseReturnDecrypted(DB_PASSWD, $SETTINGS);
1990
    DB::$dbName = DB_NAME;
1991
    DB::$port = DB_PORT;
1992
    DB::$encoding = DB_ENCODING;
1993
    //DB::$errorHandler = true;
1994
1995
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
1996
    $link->set_charset(DB_ENCODING);
1997
1998
    if (file_exists($tp_config_file) === false || $action === 'rebuild') {
1999
        // perform a copy
2000
        if (file_exists($tp_config_file)) {
2001
            if (!copy($tp_config_file, $tp_config_file.'.'.date('Y_m_d_His', time()))) {
2002
                return "ERROR: Could not copy file '".$tp_config_file."'";
2003
            }
2004
        }
2005
2006
        // regenerate
2007
        $data = array();
2008
        $data[0] = "<?php\n";
2009
        $data[1] = "global \$SETTINGS;\n";
2010
        $data[2] = "\$SETTINGS = array (\n";
2011
        $rows = DB::query(
2012
            'SELECT * FROM '.prefixTable('misc').' WHERE type=%s',
2013
            'admin'
2014
        );
2015
        foreach ($rows as $record) {
2016
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
2017
        }
2018
        array_push($data, ");\n");
2019
        $data = array_unique($data);
2020
    } elseif ($action === 'update' && empty($field) === false) {
2021
        $data = file($tp_config_file);
2022
        $inc = 0;
2023
        $bFound = false;
2024
        foreach ($data as $line) {
2025
            if (stristr($line, ');')) {
2026
                break;
2027
            }
2028
2029
            if (stristr($line, "'".$field."' => '")) {
2030
                $data[$inc] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n";
2031
                $bFound = true;
2032
                break;
2033
            }
2034
            ++$inc;
2035
        }
2036
        if ($bFound === false) {
2037
            $data[($inc)] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n);\n";
2038
        }
2039
    }
2040
2041
    // update file
2042
    file_put_contents($tp_config_file, implode('', isset($data) ? $data : array()));
2043
2044
    return true;
2045
}
2046
2047
/*
2048
** Permits to replace &#92; to permit correct display
2049
*/
2050
/**
2051
 * @param string $input
2052
 */
2053
function handleBackslash($input)
2054
{
2055
    return str_replace('&amp;#92;', '&#92;', $input);
2056
}
2057
2058
/*
2059
** Permits to loas settings
2060
*/
2061
function loadSettings()
2062
{
2063
    global $SETTINGS;
2064
2065
    /* LOAD CPASSMAN SETTINGS */
2066
    if (!isset($SETTINGS['loaded']) || $SETTINGS['loaded'] != 1) {
2067
        $SETTINGS['duplicate_folder'] = 0; //by default, this is set to 0;
2068
        $SETTINGS['duplicate_item'] = 0; //by default, this is set to 0;
2069
        $SETTINGS['number_of_used_pw'] = 5; //by default, this value is set to 5;
2070
        $settings = array();
2071
2072
        $rows = DB::query(
2073
            'SELECT * FROM '.prefixTable('misc').' WHERE type=%s_type OR type=%s_type2',
2074
            array(
2075
                'type' => 'admin',
2076
                'type2' => 'settings',
2077
            )
2078
        );
2079
        foreach ($rows as $record) {
2080
            if ($record['type'] === 'admin') {
2081
                $SETTINGS[$record['intitule']] = $record['valeur'];
2082
            } else {
2083
                $settings[$record['intitule']] = $record['valeur'];
2084
            }
2085
        }
2086
        $SETTINGS['loaded'] = 1;
2087
        $SETTINGS['default_session_expiration_time'] = 5;
2088
    }
2089
}
2090
2091
/*
2092
** check if folder has custom fields.
2093
** Ensure that target one also has same custom fields
2094
*/
2095
function checkCFconsistency($source_id, $target_id)
2096
{
2097
    $source_cf = array();
2098
    $rows = DB::QUERY(
2099
        'SELECT id_category
2100
        FROM '.prefixTable('categories_folders').'
2101
        WHERE id_folder = %i',
2102
        $source_id
2103
    );
2104
    foreach ($rows as $record) {
2105
        array_push($source_cf, $record['id_category']);
2106
    }
2107
2108
    $target_cf = array();
2109
    $rows = DB::QUERY(
2110
        'SELECT id_category
2111
        FROM '.prefixTable('categories_folders').'
2112
        WHERE id_folder = %i',
2113
        $target_id
2114
    );
2115
    foreach ($rows as $record) {
2116
        array_push($target_cf, $record['id_category']);
2117
    }
2118
2119
    $cf_diff = array_diff($source_cf, $target_cf);
2120
    if (count($cf_diff) > 0) {
2121
        return false;
2122
    }
2123
2124
    return true;
2125
}
2126
2127
/**
2128
 * Shall we crypt/decrypt.
2129
 *
2130
 * @param string $filename_to_rework File name
2131
 * @param string $filename_status    Its status
2132
 * @param array  $SETTINGS           Settings
2133
 */
2134
function encryptOrDecryptFile(
2135
    $filename_to_rework,
2136
    $filename_status,
2137
    $SETTINGS
2138
) {
2139
    // Include librairies & connect to DB
2140
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
2141
    DB::$host = DB_HOST;
2142
    DB::$user = DB_USER;
2143
    DB::$password = defuseReturnDecrypted(DB_PASSWD, $SETTINGS);
2144
    DB::$dbName = DB_NAME;
2145
    DB::$port = DB_PORT;
2146
    DB::$encoding = DB_ENCODING;
2147
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
2148
    $link->set_charset(DB_ENCODING);
2149
2150
    // Get file info in DB
2151
    $fileInfo = DB::queryfirstrow(
2152
        'SELECT id FROM '.prefixTable('files').' WHERE file = %s',
2153
        filter_var($filename_to_rework, FILTER_SANITIZE_STRING)
2154
    );
2155
    if (empty($fileInfo['id']) === false) {
2156
        // Load PhpEncryption library
2157
        $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
2158
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
2159
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
2160
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
2161
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
2162
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
2163
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
2164
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
2165
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
2166
        include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
2167
2168
        // Get KEY
2169
        $ascii_key = file_get_contents(SECUREPATH.'/teampass-seckey.txt');
2170
2171
        if (isset($SETTINGS['enable_attachment_encryption'])
2172
            && $SETTINGS['enable_attachment_encryption'] === '1'
2173
            && isset($filename_status) === true
2174
            && ($filename_status === 'clear' || $filename_status === '0')
2175
        ) {
2176
            // File needs to be encrypted
2177
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework) === true) {
2178
                // Make a copy of file
2179
                if (copy(
2180
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2181
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.'.copy'
2182
                )
2183
                    === false
2184
                ) {
2185
                    return;
2186
                } else {
2187
                    // Do a bck
2188
                    copy(
2189
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2190
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.'.bck'
2191
                    );
2192
                }
2193
2194
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
2195
2196
                // Now encrypt the file with saltkey
2197
                $err = '';
2198
                try {
2199
                    \Defuse\Crypto\File::encryptFile(
2200
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.'.copy',
2201
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2202
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2203
                    );
2204
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2205
                    $err = 'An attack! Either the wrong key was loaded, or the ciphertext has changed since it was created either corrupted in the database or intentionally modified by someone trying to carry out an attack.';
2206
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2207
                    $err = $ex;
2208
                } catch (Defuse\Crypto\Exception\IOException $ex) {
2209
                    $err = $ex;
2210
                }
2211
                if (empty($err) === false) {
2212
                    echo $err;
2213
                }
2214
2215
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.'.copy');
2216
2217
                // update table
2218
                DB::update(
2219
                    prefixTable('files'),
2220
                    array(
2221
                        'status' => 'encrypted',
2222
                        ),
2223
                    'id = %i',
2224
                    $fileInfo['id']
2225
                );
2226
            }
2227
        } elseif (isset($SETTINGS['enable_attachment_encryption'])
2228
            && $SETTINGS['enable_attachment_encryption'] === '0'
2229
            && isset($filename_status)
2230
            && $filename_status === 'encrypted'
2231
        ) {
2232
            // file needs to be decrypted
2233
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
2234
                // make a copy of file
2235
                if (!copy(
2236
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2237
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.'.copy'
2238
                )) {
2239
                    return;
2240
                } else {
2241
                    // do a bck
2242
                    copy(
2243
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2244
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.'.bck'
2245
                    );
2246
                }
2247
2248
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
2249
2250
                // Now encrypt the file with saltkey
2251
                $err = '';
2252
                try {
2253
                    \Defuse\Crypto\File::decryptFile(
2254
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.'.copy',
2255
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2256
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2257
                    );
2258
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2259
                    $err = 'An attack! Either the wrong key was loaded, or the ciphertext has changed since it was created either corrupted in the database or intentionally modified by someone trying to carry out an attack.';
2260
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2261
                    $err = $ex;
2262
                } catch (Defuse\Crypto\Exception\IOException $ex) {
2263
                    $err = $ex;
2264
                }
2265
                if (empty($err) === false) {
2266
                    echo $err;
2267
                }
2268
2269
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.'.copy');
2270
2271
                // update table
2272
                DB::update(
2273
                    prefixTable('files'),
2274
                    array(
2275
                        'status' => 'clear',
2276
                        ),
2277
                    'id = %i',
2278
                    $fileInfo['id']
2279
                );
2280
            }
2281
        }
2282
    }
2283
2284
    // Exit
2285
    return false;
2286
}
2287
2288
/**
2289
 * Will encrypte/decrypt a fil eusing Defuse.
2290
 *
2291
 * @param string $type        can be either encrypt or decrypt
2292
 * @param string $source_file path to source file
2293
 * @param string $target_file path to target file
2294
 * @param array  $SETTINGS    Settings
2295
 * @param string $password    A password
2296
 *
2297
 * @return string|bool
2298
 */
2299
function prepareFileWithDefuse(
2300
    $type,
2301
    $source_file,
2302
    $target_file,
2303
    $SETTINGS,
2304
    $password = null
2305
) {
2306
    // Load AntiXSS
2307
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2308
    $antiXss = new protect\AntiXSS\AntiXSS();
2309
2310
    // Protect against bad inputs
2311
    if (is_array($source_file) === true || is_array($target_file) === true) {
1 ignored issue
show
introduced by
The condition is_array($target_file) === true is always false.
Loading history...
2312
        return 'error_cannot_be_array';
2313
    }
2314
2315
    // Sanitize
2316
    $source_file = $antiXss->xss_clean($source_file);
2317
    $target_file = $antiXss->xss_clean($target_file);
2318
2319
    // load PhpEncryption library
2320
    $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
2321
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
2322
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
2323
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
2324
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
2325
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
2326
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
2327
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
2328
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
2329
    include_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
2330
2331
    if (empty($password) === true || is_null($password) === true) {
2332
        /*
2333
        File encryption/decryption is done with the SALTKEY
2334
         */
2335
2336
        // get KEY
2337
        $ascii_key = file_get_contents(SECUREPATH.'/teampass-seckey.txt');
2338
2339
        // Now perform action on the file
2340
        $err = '';
2341
        if ($type === 'decrypt') {
2342
            try {
2343
                \Defuse\Crypto\File::decryptFile(
2344
                    $source_file,
2345
                    $target_file,
2346
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2347
                );
2348
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2349
                $err = 'decryption_not_possible';
2350
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2351
                $err = $ex;
2352
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2353
                $err = $ex;
2354
            }
2355
        } elseif ($type === 'encrypt') {
2356
            try {
2357
                \Defuse\Crypto\File::encryptFile(
2358
                    $source_file,
2359
                    $target_file,
2360
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2361
                );
2362
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2363
                $err = 'encryption_not_possible';
2364
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2365
                $err = $ex;
2366
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2367
                $err = $ex;
2368
            }
2369
        }
2370
    } else {
2371
        /*
2372
        File encryption/decryption is done with special password and not the SALTKEY
2373
         */
2374
2375
        $err = '';
2376
        if ($type === 'decrypt') {
2377
            try {
2378
                \Defuse\Crypto\File::decryptFileWithPassword(
2379
                    $source_file,
2380
                    $target_file,
2381
                    $password
2382
                );
2383
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2384
                $err = 'wrong_key';
2385
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2386
                $err = $ex;
2387
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2388
                $err = $ex;
2389
            }
2390
        } elseif ($type === 'encrypt') {
2391
            try {
2392
                \Defuse\Crypto\File::encryptFileWithPassword(
2393
                    $source_file,
2394
                    $target_file,
2395
                    $password
2396
                );
2397
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2398
                $err = 'wrong_key';
2399
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2400
                $err = $ex;
2401
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2402
                $err = $ex;
2403
            }
2404
        }
2405
    }
2406
2407
    // return error
2408
    if (empty($err) === false) {
2409
        return $err;
2410
    } else {
2411
        return true;
2412
    }
2413
}
2414
2415
/*
2416
* NOT TO BE USED
2417
*/
2418
function debugTeampass($text)
2419
{
2420
    $debugFile = fopen('D:/wamp64/www/TeamPass/debug.txt', 'r+');
2421
    fputs($debugFile, $text);
0 ignored issues
show
Bug introduced by
It seems like $debugFile can also be of type false; however, parameter $handle of fputs() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2421
    fputs(/** @scrutinizer ignore-type */ $debugFile, $text);
Loading history...
2422
    fclose($debugFile);
0 ignored issues
show
Bug introduced by
It seems like $debugFile can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2422
    fclose(/** @scrutinizer ignore-type */ $debugFile);
Loading history...
2423
}
2424
2425
/**
2426
 * DELETE the file with expected command depending on server type.
2427
 *
2428
 * @param string $file Path to file
2429
 *
2430
 * @return Nothing
0 ignored issues
show
Bug introduced by
The type Nothing was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
2431
 */
2432
function fileDelete($file)
2433
{
2434
    global $SETTINGS;
2435
2436
    // Load AntiXSS
2437
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2438
    $antiXss = new protect\AntiXSS\AntiXSS();
2439
2440
    $file = $antiXss->xss_clean($file);
2441
    if (is_file($file)) {
2442
        unlink($file);
2443
    }
2444
}
2445
2446
/**
2447
 * Permits to extract the file extension.
2448
 *
2449
 * @param string $file File name
2450
 *
2451
 * @return string
2452
 */
2453
function getFileExtension($file)
2454
{
2455
    if (strpos($file, '.') === false) {
2456
        return $file;
2457
    }
2458
2459
    return substr($file, strrpos($file, '.') + 1);
2460
}
2461
2462
/**
2463
 * Permits to clean and sanitize text to be displayed.
2464
 *
2465
 * @param string $text Text to clean
2466
 * @param string $type What clean to perform
2467
 *
2468
 * @return string
2469
 */
2470
function cleanText($string, $type = null)
2471
{
2472
    global $SETTINGS;
2473
2474
    // Load AntiXSS
2475
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2476
    $antiXss = new protect\AntiXSS\AntiXSS();
2477
2478
    if ($type === 'css') {
2479
        // Escape text and quotes in UTF8 format
2480
        return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2481
    } elseif (empty($type) === true || is_null($type) === true || $type === 'html') {
2482
        // Html cleaner
2483
        return $antiXss->xss_clean($string);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $antiXss->xss_clean($string) also could return the type array which is incompatible with the documented return type string.
Loading history...
2484
    }
2485
}
2486
2487
/**
2488
 * Performs chmod operation on subfolders.
2489
 *
2490
 * @param string $dir             Parent folder
2491
 * @param int    $dirPermissions  New permission on folders
2492
 * @param int    $filePermissions New permission on files
2493
 *
2494
 * @return bool
2495
 */
2496
function chmodRecursive($dir, $dirPermissions, $filePermissions)
2497
{
2498
    $pointer_dir = opendir($dir);
2499
    $res = true;
2500
    while ($file = readdir($pointer_dir)) {
0 ignored issues
show
Bug introduced by
It seems like $pointer_dir can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2500
    while ($file = readdir(/** @scrutinizer ignore-type */ $pointer_dir)) {
Loading history...
2501
        if (($file === '.') || ($file === '..')) {
2502
            continue;
2503
        }
2504
2505
        $fullPath = $dir.'/'.$file;
2506
2507
        if (is_dir($fullPath)) {
2508
            if ($res = @chmod($fullPath, $dirPermissions)) {
2509
                $res = @chmodRecursive($fullPath, $dirPermissions, $filePermissions);
2510
            }
2511
        } else {
2512
            $res = chmod($fullPath, $filePermissions);
2513
        }
2514
        if (!$res) {
2515
            closedir($pointer_dir);
0 ignored issues
show
Bug introduced by
It seems like $pointer_dir can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2515
            closedir(/** @scrutinizer ignore-type */ $pointer_dir);
Loading history...
2516
2517
            return false;
2518
        }
2519
    }
2520
    closedir($pointer_dir);
2521
    if (is_dir($dir) && $res) {
2522
        $res = @chmod($dir, $dirPermissions);
2523
    }
2524
2525
    return $res;
2526
}
2527
2528
/**
2529
 * Check if user can access to this item.
2530
 *
2531
 * @param int $item_id ID of item
2532
 */
2533
function accessToItemIsGranted($item_id)
2534
{
2535
    global $SETTINGS;
2536
2537
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2538
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2539
2540
    // Prepare superGlobal variables
2541
    $session_groupes_visibles = $superGlobal->get('groupes_visibles', 'SESSION');
2542
    $session_list_restricted_folders_for_items = $superGlobal->get('list_restricted_folders_for_items', 'SESSION');
2543
2544
    // Load item data
2545
    $data = DB::queryFirstRow(
2546
        'SELECT id_tree
2547
        FROM '.prefixTable('items').'
2548
        WHERE id = %i',
2549
        $item_id
2550
    );
2551
2552
    // Check if user can access this folder
2553
    if (in_array($data['id_tree'], $session_groupes_visibles) === false) {
2554
        // Now check if this folder is restricted to user
2555
        if (isset($session_list_restricted_folders_for_items[$data['id_tree']])
2556
            && !in_array($item_id, $session_list_restricted_folders_for_items[$data['id_tree']])
2557
        ) {
2558
            return 'ERR_FOLDER_NOT_ALLOWED';
2559
        } else {
2560
            return 'ERR_FOLDER_NOT_ALLOWED';
2561
        }
2562
    }
2563
2564
    return true;
2565
}
2566
2567
/**
2568
 * Creates a unique key.
2569
 *
2570
 * @lenght  integer $lenght Key lenght
2571
 *
2572
 * @return string
2573
 */
2574
function uniqidReal($lenght = 13)
2575
{
2576
    // uniqid gives 13 chars, but you could adjust it to your needs.
2577
    if (function_exists('random_bytes')) {
2578
        $bytes = random_bytes(ceil($lenght / 2));
0 ignored issues
show
Bug introduced by
ceil($lenght / 2) of type double is incompatible with the type integer expected by parameter $length of random_bytes(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2578
        $bytes = random_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2579
    } elseif (function_exists('openssl_random_pseudo_bytes')) {
2580
        $bytes = openssl_random_pseudo_bytes(ceil($lenght / 2));
0 ignored issues
show
Bug introduced by
ceil($lenght / 2) of type double is incompatible with the type integer expected by parameter $length of openssl_random_pseudo_bytes(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2580
        $bytes = openssl_random_pseudo_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2581
    } else {
2582
        throw new Exception('no cryptographically secure random function available');
2583
    }
2584
2585
    return substr(bin2hex($bytes), 0, $lenght);
2586
}
2587
2588
2589
/**
2590
 * Obfuscate an email
2591
 *
2592
 * @param string $email Email address
2593
 *
2594
 * @return string
2595
 */
2596
function obfuscateEmail($email)
2597
{
2598
    $prop = 2;
2599
    $start = '';
2600
    $end = '';
2601
    $domain = substr(strrchr($email, '@'), 1);
2602
    $mailname = str_replace($domain, '', $email);
2603
    $name_l = strlen($mailname);
2604
    $domain_l = strlen($domain);
2605
    for ($i = 0; $i <= $name_l / $prop - 1; ++$i) {
2606
        $start .= 'x';
2607
    }
2608
2609
    for ($i = 0; $i <= $domain_l / $prop - 1; ++$i) {
2610
        $end .= 'x';
2611
    }
2612
2613
    return substr_replace($mailname, $start, 2, $name_l / $prop)
2614
        .substr_replace($domain, $end, 2, $domain_l / $prop);
2615
}
2616
2617
2618
/**
2619
 * Permits to get LDAP information about a user
2620
 *
2621
 * @param string $username User name
2622
 * @param string $password User password
2623
 * @param array  $SETTINGS Settings
2624
 *
2625
 * @return string
2626
 */
2627
function connectLDAP($username, $password, $SETTINGS)
2628
{
2629
    $ldapInfo = '';
2630
2631
    // Prepare LDAP connection if set up
2632
    
2633
    if ($SETTINGS['ldap_type'] === 'posix-search') {
2634
        $ldapInfo = ldapPosixSearch(
2635
            $username,
2636
            $password,
2637
            $SETTINGS
2638
        );
2639
    } else {
2640
        $ldapInfo = ldapPosixAndWindows(
2641
            $username,
2642
            $password,
2643
            $SETTINGS
2644
        );
2645
    }
2646
2647
    return json_encode($ldapInfo);
2648
}
2649
2650
2651
/**
2652
 * Undocumented function
2653
 *
2654
 * @param string $username Username
2655
 * @param string $password Password
2656
 * @param array  $SETTINGS Settings
2657
 *
2658
 * @return array
2659
 */
2660
function ldapPosixSearch($username, $password, $SETTINGS)
2661
{
2662
    $ldapURIs = '';
2663
    $user_email = '';
2664
    $user_found = false;
2665
    $user_lastname = '';
2666
    $user_name = '';
2667
    $ldapConnection = false;
2668
2669
    foreach (explode(",", $SETTINGS['ldap_domain_controler']) as $domainControler) {
2670
        if ($SETTINGS['ldap_ssl'] == 1) {
2671
            $ldapURIs .= "ldaps://".$domainControler.":".$SETTINGS['ldap_port']." ";
2672
        } else {
2673
            $ldapURIs .= "ldap://".$domainControler.":".$SETTINGS['ldap_port']." ";
2674
        }
2675
    }
2676
    $ldapconn = ldap_connect($ldapURIs);
2677
2678
    if ($SETTINGS['ldap_tls']) {
2679
        ldap_start_tls($ldapconn);
2680
    }
2681
    ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
2682
    ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
2683
2684
    // Is LDAP connection ready?
2685
    if ($ldapconn !== false) {
2686
        // Should we bind the connection?
2687
        if (empty($SETTINGS['ldap_bind_dn']) === false
2688
            && empty($SETTINGS['ldap_bind_passwd']) === false
2689
        ) {
2690
            $ldapbind = ldap_bind($ldapconn, $SETTINGS['ldap_bind_dn'], $SETTINGS['ldap_bind_passwd']);
2691
        } else {
2692
            $ldapbind = false;
2693
        }
2694
        if ((empty($SETTINGS['ldap_bind_dn']) === true && empty($SETTINGS['ldap_bind_passwd']) === true)
2695
            || $ldapbind === true
2696
        ) {
2697
            $filter = "(&(".$SETTINGS['ldap_user_attribute']."=".$username.")(objectClass=".$SETTINGS['ldap_object_class']."))";
2698
            $result = ldap_search(
2699
                $ldapconn,
2700
                $SETTINGS['ldap_search_base'],
2701
                $filter,
2702
                array('dn', 'mail', 'givenname', 'sn', 'samaccountname')
2703
            );
2704
2705
            // Check if user was found in AD
2706
            if (ldap_count_entries($ldapconn, $result) > 0) {
2707
                // Get user's info and especially the DN
2708
                $result = ldap_get_entries($ldapconn, $result);
2709
                $user_dn = $result[0]['dn'];
2710
                $user_email = $result[0]['mail'][0];
2711
                $user_lastname = $result[0]['sn'][0];
2712
                $user_name = isset($result[0]['givenname'][0]) === true ? $result[0]['givenname'][0] : '';
2713
                $user_found = true;
2714
2715
                // Should we restrain the search in specified user groups
2716
                $GroupRestrictionEnabled = false;
2717
                if (isset($SETTINGS['ldap_usergroup']) === true
2718
                    && empty($SETTINGS['ldap_usergroup']) === false
2719
                ) {
2720
                    // New way to check User's group membership
2721
                    $filter_group = "memberUid=".$username;
2722
                    $result_group = ldap_search(
2723
                        $ldapconn,
2724
                        $SETTINGS['ldap_search_base'],
2725
                        $filter_group,
2726
                        array('dn', 'samaccountname')
2727
                    );
2728
2729
                    if ($result_group) {
0 ignored issues
show
introduced by
$result_group is of type resource, thus it always evaluated to false.
Loading history...
2730
                        $entries = ldap_get_entries($ldapconn, $result_group);
2731
2732
                        if ($entries['count'] > 0) {
2733
                            // Now check if group fits
2734
                            for ($i = 0; $i < $entries['count']; $i++) {
2735
                                $parsr = ldap_explode_dn($entries[$i]['dn'], 0);
2736
                                if (str_replace(array('CN=', 'cn='), '', $parsr[0]) === $SETTINGS['ldap_usergroup']) {
2737
                                    $GroupRestrictionEnabled = true;
2738
                                    break;
2739
                                }
2740
                            }
2741
                        }
2742
                    }
2743
                }
2744
2745
                // Is user in the LDAP?
2746
                if ($GroupRestrictionEnabled === true
2747
                    || ($GroupRestrictionEnabled === false
2748
                    && (isset($SETTINGS['ldap_usergroup']) === false
2749
                    || (isset($SETTINGS['ldap_usergroup']) === true
2750
                    && empty($SETTINGS['ldap_usergroup']) === true)))
2751
                ) {
2752
                    // Try to auth inside LDAP
2753
                    $ldapbind = ldap_bind($ldapconn, $user_dn, $password);
2754
                    if ($ldapbind === true) {
2755
                        $ldapConnection = true;
2756
                    } else {
2757
                        $ldapConnection = false;
2758
                    }
2759
                }
2760
            } else {
2761
                $ldapConnection = false;
2762
            }
2763
        } else {
2764
            $ldapConnection = false;
2765
        }
2766
    } else {
2767
        $ldapConnection = false;
2768
    }
2769
2770
    return array(
2771
        'lastname' => $user_lastname,
2772
        'name' => $user_name,
2773
        'email' => $user_email,
2774
        'auth_success' => $ldapConnection,
2775
        'user_found' => $user_found
2776
    );
2777
}
2778
2779
/**
2780
 * Undocumented function
2781
 *
2782
 * @param string $username Username
2783
 * @param string $password Password
2784
 * @param array  $SETTINGS Settings
2785
 *
2786
 * @return array
2787
 */
2788
function ldapPosixAndWindows($username, $password, $SETTINGS)
2789
{
2790
    $user_email = '';
2791
    $user_found = false;
2792
    $user_lastname = '';
2793
    $user_name = '';
2794
    $ldapConnection = false;
2795
    $ldap_suffix = '';
2796
2797
    //Multiple Domain Names
2798
    if (strpos(html_entity_decode($username), '\\') === true) {
2799
        $ldap_suffix = "@".substr(html_entity_decode($username), 0, strpos(html_entity_decode($username), '\\'));
0 ignored issues
show
Unused Code introduced by
The assignment to $ldap_suffix is dead and can be removed.
Loading history...
2800
        $username = substr(html_entity_decode($username), strpos(html_entity_decode($username), '\\') + 1);
2801
    }
2802
    
2803
    $adldap = new SplClassLoader('adLDAP', '../includes/libraries/LDAP');
2804
    $adldap->register();
2805
2806
    // Posix style LDAP handles user searches a bit differently
2807
    if ($SETTINGS['ldap_type'] === 'posix') {
2808
        $ldap_suffix = ','.$SETTINGS['ldap_suffix'].','.$SETTINGS['ldap_domain_dn'];
2809
    } else {
2810
        // case where $SETTINGS['ldap_type'] equals 'windows'
2811
        //Multiple Domain Names
2812
        $ldap_suffix = $SETTINGS['ldap_suffix'];
2813
    }
2814
2815
    // Ensure no double commas exist in ldap_suffix
2816
    $ldap_suffix = str_replace(',,', ',', $ldap_suffix);
2817
2818
    // Create LDAP connection
2819
    $adldap = new adLDAP\adLDAP(
2820
        array(
2821
            'base_dn' => $SETTINGS['ldap_domain_dn'],
2822
            'account_suffix' => $ldap_suffix,
2823
            'domain_controllers' => explode(",", $SETTINGS['ldap_domain_controler']),
2824
            'ad_port' => $SETTINGS['ldap_port'],
2825
            'use_ssl' => $SETTINGS['ldap_ssl'],
2826
            'use_tls' => $SETTINGS['ldap_tls']
2827
        )
2828
    );
2829
2830
    // OpenLDAP expects an attribute=value pair
2831
    if ($SETTINGS['ldap_type'] === 'posix') {
2832
        $auth_username = $SETTINGS['ldap_user_attribute'].'='.$username;
2833
    } else {
2834
        $auth_username = $username;
2835
    }
2836
2837
    // Authenticate the user
2838
    if ($adldap->authenticate($auth_username, html_entity_decode($password))) {
2839
        // Get user info
2840
        $result = $adldap->user()->info($auth_username, array('mail', 'givenname', 'sn'));
2841
        $user_email = $result[0]['mail'][0];
2842
        $user_lastname = $result[0]['sn'][0];
2843
        $user_name = $result[0]['givenname'][0];
2844
        $user_found = true;
2845
2846
        // Is user in allowed group
2847
        if (isset($SETTINGS['ldap_allowed_usergroup']) === true
2848
            && empty($SETTINGS['ldap_allowed_usergroup']) === false
2849
        ) {
2850
            if ($adldap->user()->inGroup($auth_username, $SETTINGS['ldap_allowed_usergroup']) === true) {
2851
                $ldapConnection = true;
2852
            } else {
2853
                $ldapConnection = false;
2854
            }
2855
        } else {
2856
            $ldapConnection = true;
2857
        }
2858
    } else {
2859
        $ldapConnection = false;
2860
    }
2861
2862
    return array(
2863
        'lastname' => $user_lastname,
2864
        'name' => $user_name,
2865
        'email' => $user_email,
2866
        'auth_success' => $ldapConnection,
2867
        'user_found' => $user_found
2868
    );
2869
}
2870
2871
//--------------------------------
2872
2873
/**
2874
 * Perform a Query.
2875
 *
2876
 * @param array  $SETTINGS Teamapss settings
2877
 * @param string $fields   Fields to use
2878
 * @param string $table    Table to use
2879
 *
2880
 * @return array
2881
 */
2882
function performDBQuery($SETTINGS, $fields, $table)
2883
{
2884
    // include librairies & connect to DB
2885
    include_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
2886
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
2887
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
2888
    $link->set_charset(DB_ENCODING);
2889
2890
    // Insert log in DB
2891
    return DB::query(
2892
        'SELECT '.$fields.'
2893
        FROM '.prefixTable($table)
2894
    );
2895
}
2896