Passed
Push — development ( f80c08...9f32e1 )
by Nils
06:26
created

connectLDAP()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 21
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 2
eloc 12
c 2
b 0
f 0
nc 2
nop 3
dl 0
loc 21
rs 9.8666
1
<?php
2
/**
3
 *
4
 * @package       main.functions.php
5
 * @author        Nils Laumaillé <[email protected]>
6
 * @version       2.1.27
7
 * @copyright     2009-2018 Nils Laumaillé
8
 * @license       GNU GPL-3.0
9
 * @link
10
 */
11
12
//define pbkdf2 iteration count
13
define('ITCOUNT', '2072');
14
15
if (!isset($_SESSION['CPM']) || $_SESSION['CPM'] != 1) {
16
    die('Hacking attempt...');
17
}
18
19
// Load config if $SETTINGS not defined
20
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
21
    if (file_exists('../includes/config/tp.config.php')) {
22
        include_once '../includes/config/tp.config.php';
23
    } elseif (file_exists('./includes/config/tp.config.php')) {
24
        include_once './includes/config/tp.config.php';
25
    } elseif (file_exists('../../includes/config/tp.config.php')) {
26
        include_once '../../includes/config/tp.config.php';
27
    } else {
28
        //throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
29
    }
30
}
31
32
// load phpCrypt
33
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
34
    include_once '../includes/libraries/phpcrypt/phpCrypt.php';
35
    include_once '../includes/config/settings.php';
36
} else {
37
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/phpcrypt/phpCrypt.php';
38
    include_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
39
}
40
41
// Prepare PHPCrypt class calls
42
use PHP_Crypt\PHP_Crypt as PHP_Crypt;
43
44
// Prepare Encryption class calls
45
use \Defuse\Crypto\Crypto;
46
use \Defuse\Crypto\Exception as Ex;
47
48
//Generate N# of random bits for use as salt
49
/**
50
 * @param integer $size
51
 */
52
function getBits($size)
53
{
54
    $str = '';
55
    $var_x = $size + 10;
56
    for ($var_i = 0; $var_i < $var_x; $var_i++) {
57
        $str .= base_convert(mt_rand(1, 36), 10, 36);
58
    }
59
    return substr($str, 0, $size);
60
}
61
62
//generate pbkdf2 compliant hash
63
function strHashPbkdf2($var_p, $var_s, $var_c, $var_kl, $var_a = 'sha256', $var_st = 0)
64
{
65
    $var_kb = $var_st + $var_kl; // Key blocks to compute
66
    $var_dk = ''; // Derived key
67
68
    for ($block = 1; $block <= $var_kb; $block++) { // Create key
69
        $var_ib = $var_h = hash_hmac($var_a, $var_s.pack('N', $block), $var_p, true); // Initial hash for this block
70
        for ($var_i = 1; $var_i < $var_c; $var_i++) { // Perform block iterations
71
            $var_ib ^= ($var_h = hash_hmac($var_a, $var_h, $var_p, true)); // XOR each iterate
72
        }
73
        $var_dk .= $var_ib; // Append iterated block
74
    }
75
    return substr($var_dk, $var_st, $var_kl); // Return derived key of correct length
76
}
77
78
/**
79
 * stringUtf8Decode()
80
 *
81
 * utf8_decode
82
 */
83
function stringUtf8Decode($string)
84
{
85
    return str_replace(" ", "+", utf8_decode($string));
86
}
87
88
/**
89
 * encryptOld()
90
 *
91
 * crypt a string
92
 * @param string $text
93
 */
94
function encryptOld($text, $personalSalt = "")
95
{
96
    if (empty($personalSalt) === false) {
97
        return trim(
98
            base64_encode(
99
                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

99
                /** @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...
100
                    MCRYPT_RIJNDAEL_256,
101
                    $personalSalt,
102
                    $text,
103
                    MCRYPT_MODE_ECB,
104
                    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

104
                    /** @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...
105
                        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

105
                        /** @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...
106
                        MCRYPT_RAND
107
                    )
108
                )
109
            )
110
        );
111
    }
112
113
    // If $personalSalt is not empty
114
    return trim(
115
        base64_encode(
116
            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

116
            /** @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...
117
                MCRYPT_RIJNDAEL_256,
118
                SALT,
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
119
                $text,
120
                MCRYPT_MODE_ECB,
121
                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

121
                /** @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...
122
                    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

122
                    /** @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...
123
                    MCRYPT_RAND
124
                )
125
            )
126
        )
127
    );
128
}
129
130
/**
131
 * decryptOld()
132
 *
133
 * decrypt a crypted string
134
 */
135
function decryptOld($text, $personalSalt = "")
136
{
137
    if (!empty($personalSalt)) {
138
        return trim(
139
            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

139
            /** @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...
140
                MCRYPT_RIJNDAEL_256,
141
                $personalSalt,
142
                base64_decode($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
    // No personal SK
153
    return trim(
154
        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

154
        /** @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...
155
            MCRYPT_RIJNDAEL_256,
156
            SALT,
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
157
            base64_decode($text),
158
            MCRYPT_MODE_ECB,
159
            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

159
            /** @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...
160
                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

160
                /** @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...
161
                MCRYPT_RAND
162
            )
163
        )
164
    );
165
}
166
167
/**
168
 * encrypt()
169
 *
170
 * crypt a string
171
 * @param string $decrypted
172
 */
173
function encrypt($decrypted, $personalSalt = "")
174
{
175
    global $SETTINGS;
176
177
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
178
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
179
    } else {
180
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
181
    }
182
183
    if (!empty($personalSalt)) {
184
        $staticSalt = $personalSalt;
185
    } else {
186
        $staticSalt = SALT;
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
187
    }
188
189
    //set our salt to a variable
190
    // Get 64 random bits for the salt for pbkdf2
191
    $pbkdf2Salt = getBits(64);
192
    // generate a pbkdf2 key to use for the encryption.
193
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
194
    // Build $init_vect and $ivBase64.  We use a block size of 256 bits (AES compliant)
195
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
196
    $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

196
    $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

196
    $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...
197
198
    //base64 trim
199
    if (strlen($ivBase64 = rtrim(base64_encode($init_vect), '=')) != 43) {
200
        return false;
201
    }
202
    // Encrypt $decrypted
203
    $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

203
    $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...
204
    // MAC the encrypted text
205
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
206
    // We're done!
207
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
208
}
209
210
/**
211
 * decrypt()
212
 *
213
 * decrypt a crypted string
214
 */
215
function decrypt($encrypted, $personalSalt = "")
216
{
217
    global $SETTINGS;
218
219
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
220
        include_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
221
    } else {
222
        include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
223
    }
224
225
    if (!empty($personalSalt)) {
226
        $staticSalt = $personalSalt;
227
    } else {
228
        $staticSalt = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
229
    }
230
    //base64 decode the entire payload
231
    $encrypted = base64_decode($encrypted);
232
    // get the salt
233
    $pbkdf2Salt = substr($encrypted, -64);
234
    //remove the salt from the string
235
    $encrypted = substr($encrypted, 0, -64);
236
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
237
    // Retrieve $init_vect which is the first 22 characters plus ==, base64_decoded.
238
    $init_vect = base64_decode(substr($encrypted, 0, 43).'==');
239
    // Remove $init_vect from $encrypted.
240
    $encrypted = substr($encrypted, 43);
241
    // Retrieve $mac which is the last 64 characters of $encrypted.
242
    $mac = substr($encrypted, -64);
243
    // Remove the last 64 chars from encrypted (remove MAC)
244
    $encrypted = substr($encrypted, 0, -64);
245
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
246
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
247
        return false;
248
    }
249
    // Decrypt the data.
250
    $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

250
    $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...
251
    // Yay!
252
    return $decrypted;
253
}
254
255
256
/**
257
 * genHash()
258
 *
259
 * Generate a hash for user login
260
 * @param string $password
261
 */
262
function bCrypt($password, $cost)
263
{
264
    $salt = sprintf('$2y$%02d$', $cost);
265
    if (function_exists('openssl_random_pseudo_bytes')) {
266
        $salt .= bin2hex(openssl_random_pseudo_bytes(11));
267
    } else {
268
        $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
269
        for ($i = 0; $i < 22; $i++) {
270
            $salt .= $chars[mt_rand(0, 63)];
271
        }
272
    }
273
    return crypt($password, $salt);
274
}
275
276
/*
277
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
278
 *
279
 * Using AES_128 and mode CBC
280
 *
281
 * $key and $init_vect have to be given in hex format
282
 */
283
function cryption_phpCrypt($string, $key, $init_vect, $type)
284
{
285
    // manage key origin
286
    if (null != SALT && $key != SALT) {
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
287
        // check key (AES-128 requires a 16 bytes length key)
288
        if (strlen($key) < 16) {
289
            for ($inc = strlen($key) + 1; $inc <= 16; $inc++) {
290
                $key .= chr(0);
291
            }
292
        } elseif (strlen($key) > 16) {
293
            $key = substr($key, 16);
294
        }
295
    }
296
297
    // load crypt
298
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
299
300
    if ($type == "encrypt") {
301
        // generate IV and encrypt
302
        $init_vect = $crypt->createIV();
303
        $encrypt = $crypt->encrypt($string);
304
        // return
305
        return array(
306
            "string" => bin2hex($encrypt),
307
            "iv" => bin2hex($init_vect),
308
            "error" => empty($encrypt) ? "ERR_ENCRYPTION_NOT_CORRECT" : ""
309
        );
310
    } elseif ($type == "decrypt") {
311
        // case if IV is empty
312
        if (empty($init_vect)) {
313
            return array(
314
                'string' => "",
315
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
316
            );
317
        }
318
319
        // convert
320
        try {
321
            $string = testHex2Bin(trim($string));
322
            $init_vect = testHex2Bin($init_vect);
323
        } catch (Exception $e) {
324
            return array(
325
                'string' => "",
326
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
327
            );
328
        }
329
330
        // load IV
331
        $crypt->IV($init_vect);
332
        // decrypt
333
        $decrypt = $crypt->decrypt($string);
334
        // return
335
        return array(
336
            'string' => str_replace(chr(0), "", $decrypt),
337
            'error' => ""
338
        );
339
    }
340
}
341
342
function testHex2Bin($val)
343
{
344
    if (!@hex2bin($val)) {
345
        throw new Exception("ERROR");
346
    }
347
    return hex2bin($val);
348
}
349
350
/**
351
 * Defuse cryption function
352
 *
353
 * @param  string $message   what to de/crypt
354
 * @param  string $ascii_key key to use
355
 * @param  string $type      operation to perform
356
 * @return array
357
 */
358
function cryption($message, $ascii_key, $type) //defuse_crypto
359
{
360
    global $SETTINGS;
361
362
    // load PhpEncryption library
363
    if (isset($SETTINGS['cpassman_dir']) === false || empty($SETTINGS['cpassman_dir']) === true) {
364
        $path = '../includes/libraries/Encryption/Encryption/';
365
    } else {
366
        $path = $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
367
    }
368
369
    include_once $path.'Crypto.php';
370
    include_once $path.'Encoding.php';
371
    include_once $path.'DerivedKeys.php';
372
    include_once $path.'Key.php';
373
    include_once $path.'KeyOrPassword.php';
374
    include_once $path.'File.php';
375
    include_once $path.'RuntimeTests.php';
376
    include_once $path.'KeyProtectedByPassword.php';
377
    include_once $path.'Core.php';
378
379
    // init
380
    $err = '';
381
    if (empty($ascii_key)) {
382
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
383
    }
384
385
    // convert KEY
386
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
387
388
    try {
389
        if ($type === "encrypt") {
390
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
391
        } elseif ($type === "decrypt") {
392
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
393
        }
394
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
395
        $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.";
396
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
397
        $err = $ex;
398
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
399
        $err = $ex;
400
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
401
        $err = $ex;
402
    } catch (Defuse\Crypto\Exception\IOException $ex) {
403
        $err = $ex;
404
    }
405
406
    return array(
407
        'string' => isset($text) ? $text : "",
408
        'error' => $err
409
    );
410
}
411
412
/**
413
 * Generating a defuse key
414
 *
415
 * @return string
416
 */
417
function defuse_generate_key()
418
{
419
    include_once '../includes/libraries/Encryption/Encryption/Crypto.php';
420
    include_once '../includes/libraries/Encryption/Encryption/Encoding.php';
421
    include_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
422
    include_once '../includes/libraries/Encryption/Encryption/Key.php';
423
    include_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
424
    include_once '../includes/libraries/Encryption/Encryption/File.php';
425
    include_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
426
    include_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
427
    include_once '../includes/libraries/Encryption/Encryption/Core.php';
428
429
    $key = \Defuse\Crypto\Key::createNewRandomKey();
430
    $key = $key->saveToAsciiSafeString();
431
    return $key;
432
}
433
434
/**
435
 * Generate a Defuse personal key
436
 *
437
 * @param  string $psk psk used
438
 * @return string
439
 */
440
function defuse_generate_personal_key($psk)
441
{
442
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
443
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
444
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
445
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
446
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
447
    require_once '../includes/libraries/Encryption/Encryption/File.php';
448
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
449
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
450
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
451
452
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
453
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
454
455
    return $protected_key_encoded; // save this in user table
456
}
457
458
/**
459
 * Validate persoanl key with defuse
460
 *
461
 * @param  string $psk                   the user's psk
462
 * @param  string $protected_key_encoded special key
463
 * @return string
464
 */
465
function defuse_validate_personal_key($psk, $protected_key_encoded)
466
{
467
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
468
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
469
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
470
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
471
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
472
    require_once '../includes/libraries/Encryption/Encryption/File.php';
473
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
474
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
475
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
476
477
    try {
478
        $protected_key = \Defuse\Crypto\KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
479
        $user_key = $protected_key->unlockKey($psk);
480
        $user_key_encoded = $user_key->saveToAsciiSafeString();
481
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
482
        return "Error - Major issue as the encryption is broken.";
483
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
484
        return "Error - The saltkey is not the correct one.";
485
    }
486
487
    return $user_key_encoded; // store it in session once user has entered his psk
488
}
489
490
/**
491
 * Decrypt a defuse string if encrypted
492
 *
493
 * @param  string $value Encrypted string
494
 * @return string        Decrypted string
495
 */
496
function defuse_return_decrypted($value)
497
{
498
    if (substr($value, 0, 3) === "def") {
499
        $value = cryption($value, "", "decrypt")['string'];
500
    }
501
    return $value;
502
}
503
504
/**
505
 * trimElement()
506
 *
507
 * trim a string depending on a specific string
508
 * @param  string $chaine  what to trim
509
 * @param  string $element trim on what
510
 * @return string
511
 */
512
function trimElement($chaine, $element)
513
{
514
    if (!empty($chaine)) {
515
        if (is_array($chaine) === true) {
0 ignored issues
show
introduced by
The condition is_array($chaine) === true is always false.
Loading history...
516
            $chaine = implode(";", $chaine);
517
        }
518
        $chaine = trim($chaine);
519
        if (substr($chaine, 0, 1) == $element) {
520
            $chaine = substr($chaine, 1);
521
        }
522
        if (substr($chaine, strlen($chaine) - 1, 1) == $element) {
523
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
524
        }
525
    }
526
    return $chaine;
527
}
528
529
/**
530
 * Permits to suppress all "special" characters from string
531
 *
532
 * @param  string  $string  what to clean
533
 * @param  boolean $special use of special chars?
534
 * @return string
535
 */
536
function cleanString($string, $special = false)
537
{
538
    // Create temporary table for special characters escape
539
    $tabSpecialChar = array();
540
    for ($i = 0; $i <= 31; $i++) {
541
        $tabSpecialChar[] = chr($i);
542
    }
543
    array_push($tabSpecialChar, "<br />");
544
    if ($special == "1") {
545
        $tabSpecialChar = array_merge($tabSpecialChar, array("</li>", "<ul>", "<ol>"));
546
    }
547
548
    return str_replace($tabSpecialChar, "\n", $string);
549
}
550
551
/**
552
 * Erro manager for DB
553
 *
554
 * @param  array $params output from query
555
 * @return void
556
 */
557
function db_error_handler($params)
558
{
559
    echo "Error: ".$params['error']."<br>\n";
560
    echo "Query: ".$params['query']."<br>\n";
561
    throw new Exception("Error - Query", 1);
562
}
563
564
/**
565
 * [identifyUserRights description]
566
 * @param  string $groupesVisiblesUser  [description]
567
 * @param  string $groupesInterditsUser [description]
568
 * @param  string $isAdmin              [description]
569
 * @param  string $idFonctions          [description]
570
 * @return string                       [description]
571
 */
572
function identifyUserRights(
573
    $groupesVisiblesUser,
574
    $groupesInterditsUser,
575
    $isAdmin,
576
    $idFonctions,
577
    $server,
578
    $user,
579
    $pass,
580
    $database,
581
    $port,
582
    $encoding,
583
    $SETTINGS
584
) {
585
    //load ClassLoader
586
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
587
588
    //Connect to DB
589
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
590
    $pass = defuse_return_decrypted($pass);
591
    DB::$host = $server;
592
    DB::$user = $user;
593
    DB::$password = $pass;
594
    DB::$dbName = $database;
595
    DB::$port = $port;
596
    DB::$encoding = $encoding;
597
    DB::$error_handler = true;
598
    $link = mysqli_connect($server, $user, $pass, $database, $port);
599
    $link->set_charset($encoding);
600
601
    //Build tree
602
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
603
    $tree->register();
604
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
605
606
    // Check if user is ADMINISTRATOR
607
    if ($isAdmin === '1') {
608
        $groupesVisibles = array();
609
        $_SESSION['personal_folders'] = array();
610
        $_SESSION['groupes_visibles'] = array();
611
        $_SESSION['groupes_interdits'] = array();
612
        $_SESSION['personal_visible_groups'] = array();
613
        $_SESSION['read_only_folders'] = array();
614
        $_SESSION['list_restricted_folders_for_items'] = array();
615
        $_SESSION['list_folders_editable_by_role'] = array();
616
        $_SESSION['list_folders_limited'] = array();
617
        $_SESSION['no_access_folders'] = array();
618
        $_SESSION['groupes_visibles_list'] = "";
619
        $rows = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i", 0);
620
        foreach ($rows as $record) {
621
            array_push($groupesVisibles, $record['id']);
622
        }
623
        $_SESSION['groupes_visibles'] = $groupesVisibles;
624
        $_SESSION['all_non_personal_folders'] = $groupesVisibles;
625
        // Exclude all PF
626
        $_SESSION['forbiden_pfs'] = array();
627
        $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
628
        $where->add('personal_folder=%i', 1);
629
        if (isset($SETTINGS['enable_pf_feature']) && $SETTINGS['enable_pf_feature'] == 1) {
630
            $where->add('title=%s', $_SESSION['user_id']);
631
            $where->negateLast();
632
        }
633
        // Get ID of personal folder
634
        $persfld = DB::queryfirstrow(
635
            "SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s",
636
            $_SESSION['user_id']
637
        );
638
        if (!empty($persfld['id'])) {
639
            if (!in_array($persfld['id'], $_SESSION['groupes_visibles'])) {
640
                array_push($_SESSION['groupes_visibles'], $persfld['id']);
641
                array_push($_SESSION['personal_visible_groups'], $persfld['id']);
642
                // get all descendants
643
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
644
                $tree->rebuild();
645
                $tst = $tree->getDescendants($persfld['id']);
646
                foreach ($tst as $t) {
647
                    array_push($_SESSION['groupes_visibles'], $t->id);
648
                    array_push($_SESSION['personal_visible_groups'], $t->id);
649
                }
650
            }
651
        }
652
653
        // get complete list of ROLES
654
        $tmp = explode(";", $idFonctions);
655
        $rows = DB::query(
656
            "SELECT * FROM ".prefix_table("roles_title")."
657
            ORDER BY title ASC"
658
        );
659
        foreach ($rows as $record) {
660
            if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
661
                array_push($tmp, $record['id']);
662
            }
663
        }
664
        $_SESSION['fonction_id'] = implode(";", $tmp);
665
666
        $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
667
        $_SESSION['is_admin'] = $isAdmin;
668
        // Check if admin has created Folders and Roles
669
        DB::query("SELECT * FROM ".prefix_table("nested_tree")."");
670
        $_SESSION['nb_folders'] = DB::count();
671
        DB::query("SELECT * FROM ".prefix_table("roles_title"));
672
        $_SESSION['nb_roles'] = DB::count();
673
    } else {
674
        // init
675
        $_SESSION['groupes_visibles'] = array();
676
        $_SESSION['personal_folders'] = array();
677
        $_SESSION['groupes_interdits'] = array();
678
        $_SESSION['personal_visible_groups'] = array();
679
        $_SESSION['read_only_folders'] = array();
680
        $_SESSION['fonction_id'] = $idFonctions;
681
        $groupesInterdits = array();
682
        if (is_array($groupesInterditsUser) === false) {
0 ignored issues
show
introduced by
The condition is_array($groupesInterditsUser) === false is always true.
Loading history...
683
            $groupesInterditsUser = explode(';', trimElement(/** @scrutinizer ignore-type */ $groupesInterditsUser, ";"));
684
        }
685
        if (empty($groupesInterditsUser) === false && count($groupesInterditsUser) > 0) {
686
            $groupesInterdits = $groupesInterditsUser;
687
        }
688
        $_SESSION['is_admin'] = $isAdmin;
689
        $fonctionsAssociees = explode(';', trimElement($idFonctions, ";"));
690
691
        $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
692
693
        // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
694
        foreach ($fonctionsAssociees as $roleId) {
695
            if (empty($roleId) === false) {
696
                // Get allowed folders for each Role
697
                $rows = DB::query(
698
                    "SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id=%i",
699
                    $roleId
700
                );
701
702
                if (DB::count() > 0) {
703
                    $tmp = DB::queryfirstrow(
704
                        "SELECT allow_pw_change FROM ".prefix_table("roles_title")." WHERE id = %i",
705
                        $roleId
706
                    );
707
                    foreach ($rows as $record) {
708
                        if (isset($record['folder_id']) && in_array($record['folder_id'], $listAllowedFolders) === false) {
709
                            array_push($listAllowedFolders, $record['folder_id']);
710
                        }
711
                        // Check if this group is allowed to modify any pw in allowed folders
712
                        if ($tmp['allow_pw_change'] == 1 && in_array($record['folder_id'], $listFoldersEditableByRole) === false) {
713
                            array_push($listFoldersEditableByRole, $record['folder_id']);
714
                        }
715
                    }
716
                    // Check for the users roles if some specific rights exist on items
717
                    $rows = DB::query(
718
                        "SELECT i.id_tree, r.item_id
719
                        FROM ".prefix_table("items")." as i
720
                        INNER JOIN ".prefix_table("restriction_to_roles")." as r ON (r.item_id=i.id)
721
                        WHERE r.role_id=%i
722
                        ORDER BY i.id_tree ASC",
723
                        $roleId
724
                    );
725
                    $inc = 0;
726
                    foreach ($rows as $record) {
727
                        if (isset($record['id_tree'])) {
728
                            $listFoldersLimited[$record['id_tree']][$inc] = $record['item_id'];
729
                            $inc++;
730
                        }
731
                    }
732
                }
733
            }
734
        }
735
        // Clean arrays
736
        $listAllowedFolders = array_unique($listAllowedFolders);
737
        $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ";"));
738
        
739
        // Does this user is allowed to see other items
740
        $inc = 0;
741
        $rows = DB::query(
742
            "SELECT id, id_tree FROM ".prefix_table("items")."
743
            WHERE restricted_to LIKE %ss AND inactif=%s",
744
            $_SESSION['user_id'].';',
745
            '0'
746
        );
747
        foreach ($rows as $record) {
748
            // Exclude restriction on item if folder is fully accessible
749
            if (in_array($record['id_tree'], $listAllowedFolders) === false) {
750
                $listRestrictedFoldersForItems[$record['id_tree']][$inc] = $record['id'];
751
                $inc++;
752
            }
753
        }
754
        
755
        // => Build final lists
756
        // Add user allowed folders
757
        $allowedFoldersTmp = array_unique(
758
            array_merge($listAllowedFolders, $groupesVisiblesUser)
759
        );
760
        // Exclude from allowed folders all the specific user forbidden folders
761
        $allowedFolders = array();
762
        foreach ($allowedFoldersTmp as $ident) {
763
            if (!in_array($ident, $groupesInterditsUser) && !empty($ident)) {
764
                array_push($allowedFolders, $ident);
765
            }
766
        }
767
768
        // Clean array
769
        $listAllowedFolders = array_filter(array_unique($allowedFolders));
770
771
        // Exclude all PF
772
        $_SESSION['forbiden_pfs'] = array();
773
774
        $where = new WhereClause('and');
775
        $where->add('personal_folder=%i', 1);
776
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
777
            && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
778
        ) {
779
            $where->add('title=%s', $_SESSION['user_id']);
780
            $where->negateLast();
781
        }
782
783
        $persoFlds = DB::query(
784
            "SELECT id
785
            FROM ".prefix_table("nested_tree")."
786
            WHERE %l",
787
            $where
788
        );
789
        foreach ($persoFlds as $persoFldId) {
790
            array_push($_SESSION['forbiden_pfs'], $persoFldId['id']);
791
        }
792
        // Get IDs of personal folders
793
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
794
            && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
795
        ) {
796
            $persoFld = DB::queryfirstrow(
797
                "SELECT id
798
                FROM ".prefix_table("nested_tree")."
799
                WHERE title = %s AND personal_folder = %i",
800
                $_SESSION['user_id'],
801
                1
802
            );
803
            
804
            if (empty($persoFld['id']) === false) {
805
                if (in_array($persoFld['id'], $listAllowedFolders) === false) {
806
                    array_push($_SESSION['personal_folders'], $persoFld['id']);
807
                    array_push($listAllowedFolders, $persoFld['id']);
808
                    array_push($_SESSION['personal_visible_groups'], $persoFld['id']);
809
                    
810
                    // get all descendants
811
                    $ids = $tree->getDescendants($persoFld['id'], false, false);
812
                    foreach ($ids as $ident) {
813
                        if ((int) $ident->personal_folder === 1) {
814
                            array_push($listAllowedFolders, $ident->id);
815
                            array_push($_SESSION['personal_visible_groups'], $ident->id);
816
                            array_push($_SESSION['personal_folders'], $ident->id);
817
                        }
818
                    }
819
                }
820
            }
821
822
            // get list of readonly folders when pf is disabled.
823
            $_SESSION['personal_folders'] = array_unique($_SESSION['personal_folders']);
824
            // rule - if one folder is set as W or N in one of the Role, then User has access as W
825
            foreach ($listAllowedFolders as $folderId) {
826
                if (in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders']))) === false) {
827
                    DB::query(
828
                        "SELECT *
829
                        FROM ".prefix_table("roles_values")."
830
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
831
                        $folderId,
832
                        $fonctionsAssociees,
833
                        array("W", "ND", "NE", "NDNE")
834
                    );
835
                    if (DB::count() === 0 && in_array($folderId, $groupesVisiblesUser) === false) {
836
                        array_push($listReadOnlyFolders, $folderId);
837
                    }
838
                }
839
            }
840
        } else {
841
            // get list of readonly folders when pf is disabled.
842
            // rule - if one folder is set as W in one of the Role, then User has access as W
843
            foreach ($listAllowedFolders as $folderId) {
844
                if (in_array($folderId, $listReadOnlyFolders) === false) {
845
                    DB::query(
846
                        "SELECT *
847
                        FROM ".prefix_table("roles_values")."
848
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
849
                        $folderId,
850
                        $fonctionsAssociees,
851
                        array("W", "ND", "NE", "NDNE")
852
                    );
853
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
854
                        array_push($listReadOnlyFolders, $folderId);
855
                    }
856
                }
857
            }
858
        }
859
860
        // check if change proposals on User's items
861
        if (isset($SETTINGS['enable_suggestion']) === true && $SETTINGS['enable_suggestion'] === '1') {
862
            DB::query(
863
                "SELECT *
864
                FROM ".prefix_table("items_change")." AS c
865
                LEFT JOIN ".prefix_table("log_items")." AS i ON (c.item_id = i.id_item)
866
                WHERE i.action = %s AND i.id_user = %i",
867
                "at_creation",
868
                $_SESSION['user_id']
869
            );
870
            $_SESSION['nb_item_change_proposals'] = DB::count();
871
        } else {
872
            $_SESSION['nb_item_change_proposals'] = 0;
873
        }
874
875
        $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
876
        $_SESSION['groupes_visibles'] = $listAllowedFolders;
877
        $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
878
        $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
879
        $_SESSION['read_only_folders'] = $listReadOnlyFolders;
880
        $_SESSION['no_access_folders'] = $groupesInterdits;
881
882
        $_SESSION['list_folders_limited'] = $listFoldersLimited;
883
        $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
884
        $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
885
        // Folders and Roles numbers
886
        DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")."");
887
        $_SESSION['nb_folders'] = DB::count();
888
        DB::queryfirstrow("SELECT id FROM ".prefix_table("roles_title"));
889
        $_SESSION['nb_roles'] = DB::count();
890
    }
891
892
    // update user's timestamp
893
    DB::update(
894
        prefix_table('users'),
895
        array(
896
            'timestamp' => time()
897
        ),
898
        "id=%i",
899
        $_SESSION['user_id']
900
    );
901
}
902
903
/**
904
 * updateCacheTable()
905
 *
906
 * Update the CACHE table
907
 * @param string $action
908
 */
909
function updateCacheTable($action, $ident = null)
910
{
911
    global $server, $user, $pass, $database, $port, $encoding;
912
    global $SETTINGS;
913
914
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
915
916
    //Connect to DB
917
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
918
    $pass = defuse_return_decrypted($pass);
919
    DB::$host = $server;
920
    DB::$user = $user;
921
    DB::$password = $pass;
922
    DB::$dbName = $database;
923
    DB::$port = $port;
924
    DB::$encoding = $encoding;
925
    DB::$error_handler = true;
926
    $link = mysqli_connect($server, $user, $pass, $database, $port);
927
    $link->set_charset($encoding);
928
929
    //Load Tree
930
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
931
    $tree->register();
932
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
933
934
    // Rebuild full cache table
935
    if ($action === "reload") {
936
        // truncate table
937
        DB::query("TRUNCATE TABLE ".prefix_table("cache"));
938
939
        // reload date
940
        $rows = DB::query(
941
            "SELECT *
942
            FROM ".prefix_table('items')." as i
943
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
944
            AND l.action = %s
945
            AND i.inactif = %i",
946
            'at_creation',
947
            0
948
        );
949
        foreach ($rows as $record) {
950
            if (empty($record['id_tree']) === false) {
951
                // Get all TAGS
952
                $tags = "";
953
                $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $record['id']);
954
                foreach ($itemTags as $itemTag) {
955
                    if (!empty($itemTag['tag'])) {
956
                        $tags .= $itemTag['tag']." ";
957
                    }
958
                }
959
                // Get renewal period
960
                $resNT = DB::queryfirstrow("SELECT renewal_period FROM ".prefix_table('nested_tree')." WHERE id=%i", $record['id_tree']);
961
962
                // form id_tree to full foldername
963
                $folder = "";
964
                $arbo = $tree->getPath($record['id_tree'], true);
965
                foreach ($arbo as $elem) {
966
                    if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
967
                        $elem->title = $_SESSION['login'];
968
                    }
969
                    if (empty($folder)) {
970
                        $folder = stripslashes($elem->title);
971
                    } else {
972
                        $folder .= " » ".stripslashes($elem->title);
973
                    }
974
                }
975
                // store data
976
                DB::insert(
977
                    prefix_table('cache'),
978
                    array(
979
                        'id' => $record['id'],
980
                        'label' => $record['label'],
981
                        'description' => isset($record['description']) ? $record['description'] : "",
982
                        'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : "0",
983
                        'tags' => $tags,
984
                        'id_tree' => $record['id_tree'],
985
                        'perso' => $record['perso'],
986
                        'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : "0",
987
                        'login' => isset($record['login']) ? $record['login'] : "",
988
                        'folder' => $folder,
989
                        'author' => $record['id_user'],
990
                        'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : "0",
991
                        'timestamp' => $record['date']
992
                        )
993
                );
994
            }
995
        }
996
        // UPDATE an item
997
    } elseif ($action === "update_value" && is_null($ident) === false) {
998
        // get new value from db
999
        $data = DB::queryfirstrow(
1000
            "SELECT label, description, id_tree, perso, restricted_to, login, url
1001
            FROM ".prefix_table('items')."
1002
            WHERE id=%i",
1003
            $ident
1004
        );
1005
        // Get all TAGS
1006
        $tags = "";
1007
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $ident);
1008
        foreach ($itemTags as $itemTag) {
1009
            if (!empty($itemTag['tag'])) {
1010
                $tags .= $itemTag['tag']." ";
1011
            }
1012
        }
1013
        // form id_tree to full foldername
1014
        $folder = "";
1015
        $arbo = $tree->getPath($data['id_tree'], true);
1016
        foreach ($arbo as $elem) {
1017
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1018
                $elem->title = $_SESSION['login'];
1019
            }
1020
            if (empty($folder)) {
1021
                $folder = stripslashes($elem->title);
1022
            } else {
1023
                $folder .= " » ".stripslashes($elem->title);
1024
            }
1025
        }
1026
        // finaly update
1027
        DB::update(
1028
            prefix_table('cache'),
1029
            array(
1030
                'label' => $data['label'],
1031
                'description' => $data['description'],
1032
                'tags' => $tags,
1033
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1034
                'id_tree' => $data['id_tree'],
1035
                'perso' => $data['perso'],
1036
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1037
                'login' => isset($data['login']) ? $data['login'] : "",
1038
                'folder' => $folder,
1039
                'author' => $_SESSION['user_id'],
1040
                ),
1041
            "id = %i",
1042
            $ident
1043
        );
1044
    // ADD an item
1045
    } elseif ($action === "add_value" && is_null($ident) === false) {
1046
        // get new value from db
1047
        $data = DB::queryFirstRow(
1048
            "SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
1049
            FROM ".prefix_table('items')." as i
1050
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
1051
            WHERE i.id = %i
1052
            AND l.action = %s",
1053
            $ident,
1054
            'at_creation'
1055
        );
1056
        // Get all TAGS
1057
        $tags = "";
1058
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id = %i", $ident);
1059
        foreach ($itemTags as $itemTag) {
1060
            if (!empty($itemTag['tag'])) {
1061
                $tags .= $itemTag['tag']." ";
1062
            }
1063
        }
1064
        // form id_tree to full foldername
1065
        $folder = "";
1066
        $arbo = $tree->getPath($data['id_tree'], true);
1067
        foreach ($arbo as $elem) {
1068
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1069
                $elem->title = $_SESSION['login'];
1070
            }
1071
            if (empty($folder)) {
1072
                $folder = stripslashes($elem->title);
1073
            } else {
1074
                $folder .= " » ".stripslashes($elem->title);
1075
            }
1076
        }
1077
        // finaly update
1078
        DB::insert(
1079
            prefix_table('cache'),
1080
            array(
1081
                'id' => $data['id'],
1082
                'label' => $data['label'],
1083
                'description' => $data['description'],
1084
                'tags' => (isset($tags) && !empty($tags)) ? $tags : "None",
1085
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1086
                'id_tree' => $data['id_tree'],
1087
                'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== "None") ? $data['perso'] : "0",
1088
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1089
                'login' => isset($data['login']) ? $data['login'] : "",
1090
                'folder' => $folder,
1091
                'author' => $_SESSION['user_id'],
1092
                'timestamp' => $data['date']
1093
            )
1094
        );
1095
1096
    // DELETE an item
1097
    } elseif ($action === "delete_value" && is_null($ident) === false) {
1098
        DB::delete(prefix_table('cache'), "id = %i", $ident);
1099
    }
1100
}
1101
1102
/*
1103
*
1104
*/
1105
function getStatisticsData()
1106
{
1107
    global $SETTINGS;
1108
1109
    DB::query(
1110
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1111
        0
1112
    );
1113
    $counter_folders = DB::count();
1114
1115
    DB::query(
1116
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1117
        1
1118
    );
1119
    $counter_folders_perso = DB::count();
1120
1121
    DB::query(
1122
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1123
        0
1124
    );
1125
    $counter_items = DB::count();
1126
1127
    DB::query(
1128
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1129
        1
1130
    );
1131
    $counter_items_perso = DB::count();
1132
1133
    DB::query(
1134
        "SELECT id FROM ".prefix_table("users").""
1135
    );
1136
    $counter_users = DB::count();
1137
1138
    DB::query(
1139
        "SELECT id FROM ".prefix_table("users")." WHERE admin = %i",
1140
        1
1141
    );
1142
    $admins = DB::count();
1143
1144
    DB::query(
1145
        "SELECT id FROM ".prefix_table("users")." WHERE gestionnaire = %i",
1146
        1
1147
    );
1148
    $managers = DB::count();
1149
1150
    DB::query(
1151
        "SELECT id FROM ".prefix_table("users")." WHERE read_only = %i",
1152
        1
1153
    );
1154
    $readOnly = DB::count();
1155
1156
    // list the languages
1157
    $usedLang = [];
1158
    $tp_languages = DB::query(
1159
        "SELECT name FROM ".prefix_table("languages")
1160
    );
1161
    foreach ($tp_languages as $tp_language) {
1162
        DB::query(
1163
            "SELECT * FROM ".prefix_table("users")." WHERE user_language = %s",
1164
            $tp_language['name']
1165
        );
1166
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1167
    }
1168
1169
    // get list of ips
1170
    $usedIp = [];
1171
    $tp_ips = DB::query(
1172
        "SELECT user_ip FROM ".prefix_table("users")
1173
    );
1174
    foreach ($tp_ips as $ip) {
1175
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1176
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1177
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== "none") {
1178
            $usedIp[$ip['user_ip']] = 1;
1179
        }
1180
    }
1181
1182
    return array(
1183
        "error" => "",
1184
        "stat_phpversion" => phpversion(),
1185
        "stat_folders" => $counter_folders,
1186
        "stat_folders_shared" => intval($counter_folders) - intval($counter_folders_perso),
1187
        "stat_items" => $counter_items,
1188
        "stat_items_shared" => intval($counter_items) - intval($counter_items_perso),
1189
        "stat_users" => $counter_users,
1190
        "stat_admins" => $admins,
1191
        "stat_managers" => $managers,
1192
        "stat_ro" => $readOnly,
1193
        "stat_kb" => $SETTINGS['enable_kb'],
1194
        "stat_pf" => $SETTINGS['enable_pf_feature'],
1195
        "stat_fav" => $SETTINGS['enable_favourites'],
1196
        "stat_teampassversion" => $SETTINGS['cpassman_version'],
1197
        "stat_ldap" => $SETTINGS['ldap_mode'],
1198
        "stat_agses" => $SETTINGS['agses_authentication_enabled'],
1199
        "stat_duo" => $SETTINGS['duo'],
1200
        "stat_suggestion" => $SETTINGS['enable_suggestion'],
1201
        "stat_api" => $SETTINGS['api'],
1202
        "stat_customfields" => $SETTINGS['item_extra_fields'],
1203
        "stat_syslog" => $SETTINGS['syslog_enable'],
1204
        "stat_2fa" => $SETTINGS['google_authentication'],
1205
        "stat_stricthttps" => $SETTINGS['enable_sts'],
1206
        "stat_mysqlversion" => DB::serverVersion(),
1207
        "stat_languages" => $usedLang,
1208
        "stat_country" => $usedIp
1209
    );
1210
}
1211
1212
/**
1213
 * Permits to send an email
1214
 *
1215
 * @param  string $subject     email subject
1216
 * @param  string $textMail    email message
1217
 * @param  string $email       email
1218
 * @param  array  $LANG        Language
1219
 * @param  array  $SETTINGS    settings
1220
 * @param  string $textMailAlt email message alt
1221
 * @return string some json info
1222
 */
1223
function sendEmail(
1224
    $subject,
1225
    $textMail,
1226
    $email,
1227
    $LANG,
1228
    $SETTINGS,
1229
    $textMailAlt = null
1230
) {
1231
    // CAse where email not defined
1232
    if ($email === "none") {
1233
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1234
    }
1235
1236
    // Load settings
1237
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
1238
1239
    // Load superglobal
1240
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1241
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
1242
1243
    // Get user language
1244
    $session_user_language = $superGlobal->get("user_language", "SESSION");
1245
    $user_language = isset($session_user_language) ? $session_user_language : "english";
1246
    include_once $SETTINGS['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1247
1248
    // Load library
1249
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1250
1251
    // load PHPMailer
1252
    $mail = new SplClassLoader('Email\PHPMailer', '../includes/libraries');
1253
    $mail->register();
1254
    $mail = new Email\PHPMailer\PHPMailer(true);
1255
    try {
1256
        // send to user
1257
        $mail->setLanguage("en", $SETTINGS['cpassman_dir']."/includes/libraries/Email/PHPMailer/language/");
1258
        $mail->SMTPDebug = 0; //value 1 can be used to debug - 4 for debuging connections
1259
        $mail->Port = $SETTINGS['email_port']; //COULD BE USED
1260
        $mail->CharSet = "utf-8";
1261
        if ($SETTINGS['email_security'] === "tls" || $SETTINGS['email_security'] === "ssl") {
1262
            $mail->SMTPSecure = $SETTINGS['email_security'];
1263
            $SMTPAutoTLS = true;
1264
        } else {
1265
            $mail->SMTPSecure = "";
1266
            $SMTPAutoTLS = false;
1267
        }
1268
        $mail->SMTPAutoTLS = $SMTPAutoTLS;
1269
        $mail->isSmtp(); // send via SMTP
1270
        $mail->Host = $SETTINGS['email_smtp_server']; // SMTP servers
1271
        $mail->SMTPAuth = $SETTINGS['email_smtp_auth'] == '1' ? true : false; // turn on SMTP authentication
1272
        $mail->Username = $SETTINGS['email_auth_username']; // SMTP username
1273
        $mail->Password = $SETTINGS['email_auth_pwd']; // SMTP password
1274
        $mail->From = $SETTINGS['email_from'];
1275
        $mail->FromName = $SETTINGS['email_from_name'];
1276
1277
        // Prepare for each person
1278
        foreach (explode(",", $email) as $dest) {
1279
            if (empty($dest) === false) {
1280
                $mail->addAddress($dest);
1281
            }
1282
        }
1283
1284
        // Prepare HTML
1285
        $text_html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.=
1286
        w3.org/TR/html4/loose.dtd"><html>
1287
        <head><title>Email Template</title>
1288
        <style type="text/css">
1289
        body { background-color: #f0f0f0; padding: 10px 0; margin:0 0 10px =0; }
1290
        </style></head>
1291
        <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">
1292
        <table border="0" width="100%" height="100%" cellpadding="0" cellspacing="0" bgcolor="#f0f0f0" style="border-spacing: 0;">
1293
        <tr><td style="border-collapse: collapse;"><br>
1294
            <table border="0" width="100%" cellpadding="0" cellspacing="0" bgcolor="#17357c" style="border-spacing: 0; margin-bottom: 25px;">
1295
            <tr><td style="border-collapse: collapse; padding: 11px 20px;">
1296
                <div style="max-width:150px; max-height:34px; color:#f0f0f0; font-weight:bold;">Teampass</div>
1297
            </td></tr></table></td>
1298
        </tr>
1299
        <tr><td align="center" valign="top" bgcolor="#f0f0f0" style="border-collapse: collapse; background-color: #f0f0f0;">
1300
            <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;">
1301
            <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;">
1302
            <br><div style="float:right;">'.
1303
        $textMail.
1304
        '<br><br></td></tr></table>
1305
        </td></tr></table>
1306
        <br></body></html>';
1307
1308
        $mail->WordWrap = 80; // set word wrap
1309
        $mail->isHtml(true); // send as HTML
1310
        $mail->Subject = $subject;
1311
        $mail->Body = $text_html;
1312
        $mail->AltBody = (is_null($textMailAlt) === false) ? $textMailAlt : '';
1313
        
1314
        // send email
1315
        if ($mail->send()) {
1316
            return json_encode(
1317
                array(
1318
                    "error" => "",
1319
                    "message" => $LANG['forgot_my_pw_email_sent']
1320
                )
1321
            );
1322
        } else {
1323
            return json_encode(
1324
                array(
1325
                    "error" => "error_mail_not_send",
1326
                    "message" => str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo)
1327
                )
1328
            );
1329
        }
1330
    } catch (Exception $e) {
1331
        return json_encode(
1332
            array(
1333
                "error" => "error_mail_not_send",
1334
                "message" => str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo)
1335
            )
1336
        );
1337
    }
1338
}
1339
1340
/**
1341
 * generateKey()
1342
 *
1343
 * @return
1344
 */
1345
function generateKey()
1346
{
1347
    return substr(md5(rand().rand()), 0, 15);
1348
}
1349
1350
/**
1351
 * dateToStamp()
1352
 *
1353
 * @return
1354
 */
1355
function dateToStamp($date)
1356
{
1357
    global $SETTINGS;
1358
1359
    $date = date_parse_from_format($SETTINGS['date_format'], $date);
1360
    if ($date['warning_count'] == 0 && $date['error_count'] == 0) {
1361
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1362
    } else {
1363
        return false;
1364
    }
1365
}
1366
1367
function isDate($date)
1368
{
1369
    return (strtotime($date) !== false);
1370
}
1371
1372
/**
1373
 * isUTF8()
1374
 *
1375
 * @return integer is the string in UTF8 format.
1376
 */
1377
1378
function isUTF8($string)
1379
{
1380
    if (is_array($string) === true) {
1381
        $string = $string['string'];
1382
    }
1383
    return preg_match(
1384
        '%^(?:
1385
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1386
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1387
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1388
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1389
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1390
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1391
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1392
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1393
        )*$%xs',
1394
        $string
1395
    );
1396
}
1397
1398
/*
1399
* FUNCTION
1400
* permits to prepare data to be exchanged
1401
*/
1402
/**
1403
 * @param string $type
1404
 */
1405
function prepareExchangedData($data, $type)
1406
{
1407
    global $SETTINGS;
1408
1409
    //load ClassLoader
1410
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1411
    //Load AES
1412
    $aes = new SplClassLoader('Encryption\Crypt', $SETTINGS['cpassman_dir'].'/includes/libraries');
1413
    $aes->register();
1414
1415
    if ($type == "encode") {
1416
        if (isset($SETTINGS['encryptClientServer'])
1417
            && $SETTINGS['encryptClientServer'] === "0"
1418
        ) {
1419
            return json_encode(
1420
                $data,
1421
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1422
            );
1423
        } else {
1424
            return Encryption\Crypt\aesctr::encrypt(
1425
                json_encode(
1426
                    $data,
1427
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1428
                ),
1429
                $_SESSION['key'],
1430
                256
1431
            );
1432
        }
1433
    } elseif ($type == "decode") {
1434
        if (isset($SETTINGS['encryptClientServer'])
1435
            && $SETTINGS['encryptClientServer'] === "0"
1436
        ) {
1437
            return json_decode(
1438
                $data,
1439
                true
1440
            );
1441
        } else {
1442
            return json_decode(
1443
                Encryption\Crypt\aesctr::decrypt(
1444
                    $data,
1445
                    $_SESSION['key'],
1446
                    256
1447
                ),
1448
                true
1449
            );
1450
        }
1451
    }
1452
}
1453
1454
function make_thumb($src, $dest, $desired_width)
1455
{
1456
    /* read the source image */
1457
    $source_image = imagecreatefrompng($src);
1458
    $width = imagesx($source_image);
1459
    $height = imagesy($source_image);
1460
1461
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1462
    $desired_height = floor($height * ($desired_width / $width));
1463
1464
    /* create a new, "virtual" image */
1465
    $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

1465
    $virtual_image = imagecreatetruecolor($desired_width, /** @scrutinizer ignore-type */ $desired_height);
Loading history...
1466
1467
    /* copy source image at a resized size */
1468
    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

1468
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, /** @scrutinizer ignore-type */ $desired_height, $width, $height);
Loading history...
1469
1470
    /* create the physical thumbnail image to its destination */
1471
    imagejpeg($virtual_image, $dest);
1472
}
1473
1474
/*
1475
** check table prefix in SQL query
1476
*/
1477
/**
1478
 * @param string $table
1479
 */
1480
function prefix_table($table)
1481
{
1482
    global $pre;
1483
    $safeTable = htmlspecialchars($pre.$table);
1484
    if (!empty($safeTable)) {
1485
        // sanitize string
1486
        return $safeTable;
1487
    } else {
1488
        // stop error no table
1489
        return "table_not_exists";
1490
    }
1491
}
1492
1493
/*
1494
 * Creates a KEY using PasswordLib
1495
 */
1496
function GenerateCryptKey($size = null, $secure = false, $numerals = false, $capitalize = false, $symbols = false)
1497
{
1498
    global $SETTINGS;
1499
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1500
1501
    if ($secure === true) {
1502
        $numerals = true;
1503
        $capitalize = true;
1504
        $symbols = true;
1505
    }
1506
1507
    // Load libraries
1508
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
1509
    $generator->register();
1510
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
1511
1512
    // Can we use PHP7 random_int function?
1513
    if (version_compare(phpversion(), '7.0', '>=')) {
1514
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/PasswordGenerator/RandomGenerator/Php7RandomGenerator.php';
1515
        $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
1516
    }
1517
1518
    // init
1519
    if (empty($size) === false && is_null($size) === false) {
1520
        $generator->setLength(intval($size));
1521
    }
1522
    if (empty($numerals) === false) {
1523
        $generator->setNumbers($numerals);
1524
    }
1525
    if (empty($capitalize) === false) {
1526
        $generator->setUppercase($capitalize);
1527
    }
1528
    if (empty($symbols) === false) {
1529
        $generator->setSymbols($symbols);
1530
    }
1531
1532
    // generate and send back
1533
    return $generator->generatePassword();
1534
}
1535
1536
/*
1537
* Send sysLOG message
1538
* @param string $message
1539
* @param string $host
1540
*/
1541
function send_syslog($message, $host, $port, $component = "teampass")
1542
{
1543
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1544
    $syslog_message = "<123>".date('M d H:i:s ').$component.": ".$message;
1545
    socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1546
    socket_close($sock);
1547
}
1548
1549
1550
1551
/**
1552
 * logEvents()
1553
 *
1554
 * permits to log events into DB
1555
 * @param string $type
1556
 * @param string $label
1557
 * @param string $field_1
1558
 */
1559
function logEvents($type, $label, $who, $login = null, $field_1 = null)
1560
{
1561
    global $server, $user, $pass, $database, $port, $encoding;
1562
    global $SETTINGS;
1563
1564
    if (empty($who)) {
1565
        $who = get_client_ip_server();
1566
    }
1567
1568
    // include librairies & connect to DB
1569
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1570
    $pass = defuse_return_decrypted($pass);
1571
    DB::$host = $server;
1572
    DB::$user = $user;
1573
    DB::$password = $pass;
1574
    DB::$dbName = $database;
1575
    DB::$port = $port;
1576
    DB::$encoding = $encoding;
1577
    DB::$error_handler = true;
1578
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1579
    $link->set_charset($encoding);
1580
1581
    DB::insert(
1582
        prefix_table("log_system"),
1583
        array(
1584
            'type' => $type,
1585
            'date' => time(),
1586
            'label' => $label,
1587
            'qui' => $who,
1588
            'field_1' => $field_1 === null ? "" : $field_1
1589
        )
1590
    );
1591
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1592
        if ($type == "user_mngt") {
1593
            send_syslog(
1594
                'action='.str_replace('at_', '', $label).' attribute=user user='.$who.' userid="'.$login.'" change="'.$field_1.'" ',
1595
                $SETTINGS['syslog_host'],
1596
                $SETTINGS['syslog_port'],
1597
                "teampass"
1598
            );
1599
        } else {
1600
            send_syslog(
1601
                'action='.$type.' attribute='.$label.' user='.$who.' userid="'.$login.'" ',
1602
                $SETTINGS['syslog_host'],
1603
                $SETTINGS['syslog_port'],
1604
                "teampass"
1605
            );
1606
        }
1607
    }
1608
}
1609
1610
/**
1611
 * Logs sent events
1612
 *
1613
 * @param string $ident
1614
 * @param string $item
1615
 * @param string $id_user
1616
 * @param string $action
1617
 * @param string $login
1618
 * @param string $raison
1619
 * @param string $encryption_type
1620
 * @return void
1621
 */
1622
function logItems(
1623
    $item_id,
1624
    $item_label,
1625
    $id_user,
1626
    $action,
1627
    $login = null,
1628
    $raison = null,
1629
    $encryption_type = null
1630
) {
1631
    global $server, $user, $pass, $database, $port, $encoding;
1632
    global $SETTINGS;
1633
    global $LANG;
1634
    $dataItem = '';
1635
1636
    // Exit if no item ID
1637
    if (empty($item_id) === true) {
1638
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The expression return false returns the type false which is incompatible with the documented return type void.
Loading history...
1639
    }
1640
1641
    // include librairies & connect to DB
1642
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1643
    $pass = defuse_return_decrypted($pass);
1644
    DB::$host = $server;
1645
    DB::$user = $user;
1646
    DB::$password = $pass;
1647
    DB::$dbName = $database;
1648
    DB::$port = $port;
1649
    DB::$encoding = $encoding;
1650
    DB::$error_handler = true;
1651
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1652
    $link->set_charset($encoding);
1653
1654
    // Insert log in DB
1655
    DB::insert(
1656
        prefix_table("log_items"),
1657
        array(
1658
            'id_item' => $item_id,
1659
            'date' => time(),
1660
            'id_user' => $id_user,
1661
            'action' => $action,
1662
            'raison' => $raison,
1663
            'raison_iv' => '',
1664
            'encryption_type' => is_null($encryption_type) === true ? '' : $encryption_type
1665
        )
1666
    );
1667
1668
    // SYSLOG
1669
    if (isset($SETTINGS['syslog_enable']) === true && $SETTINGS['syslog_enable'] === '1') {
1670
        // Extract reason
1671
        $attribute = explode(' : ', $raison);
1672
1673
        // Get item info if not known
1674
        if (empty($item_label) === true) {
1675
            $dataItem = DB::queryfirstrow(
1676
                "SELECT id, id_tree, label
1677
                FROM ".prefix_table("items")."
1678
                WHERE id = %i",
1679
                $item_id
1680
            );
1681
1682
            $item_label = $dataItem['label'];
1683
        }
1684
1685
        send_syslog(
1686
            'action='.str_replace('at_', '', $action).' attribute='.str_replace('at_', '', $attribute[0]).' itemno='.$item_id.' user='.addslashes($login).' itemname="'.addslashes($item_label).'"',
1687
            $SETTINGS['syslog_host'],
1688
            $SETTINGS['syslog_port'],
1689
            "teampass"
1690
        );
1691
    }
1692
1693
    // send notification if enabled
1694
    if (isset($SETTINGS['enable_email_notification_on_item_shown']) === true
1695
        && $SETTINGS['enable_email_notification_on_item_shown'] === '1'
1696
        && $action === 'at_shown'
1697
        && isset($_SESSION['listNotificationEmails']) === true
1698
    ) {
1699
        // Get info about item
1700
        if (empty($dataItem) === true || empty($item_label) === true) {
1701
            $dataItem = DB::queryfirstrow(
1702
                "SELECT id, id_tree, label
1703
                FROM ".prefix_table("items")."
1704
                WHERE id = %i",
1705
                $item_id
1706
            );
1707
            $item_label = $dataItem['label'];
1708
        }
1709
1710
        // send back infos
1711
        DB::insert(
1712
            prefix_table('emails'),
1713
            array(
1714
                'timestamp' => time(),
1715
                'subject' => $LANG['email_on_open_notification_subject'],
1716
                'body' => str_replace(
1717
                    array('#tp_user#', '#tp_item#', '#tp_link#'),
1718
                    array(
1719
                        isset($_SESSION['login']) === true ? addslashes($_SESSION['login']) : 'OTV',
1720
                        addslashes($item_label),
1721
                        $SETTINGS['cpassman_url']."/index.php?page=items&group=".$dataItem['id_tree']."&id=".$dataItem['id']
1722
                    ),
1723
                    $LANG['email_on_open_notification_mail']
1724
                ),
1725
                'receivers' => $_SESSION['listNotificationEmails'],
1726
                'status' => ''
1727
            )
1728
        );
1729
    }
1730
}
1731
1732
/*
1733
* Function to get the client ip address
1734
 */
1735
function get_client_ip_server()
1736
{
1737
    if (getenv('HTTP_CLIENT_IP')) {
1738
        $ipaddress = getenv('HTTP_CLIENT_IP');
1739
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1740
        $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1741
    } elseif (getenv('HTTP_X_FORWARDED')) {
1742
        $ipaddress = getenv('HTTP_X_FORWARDED');
1743
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1744
        $ipaddress = getenv('HTTP_FORWARDED_FOR');
1745
    } elseif (getenv('HTTP_FORWARDED')) {
1746
        $ipaddress = getenv('HTTP_FORWARDED');
1747
    } elseif (getenv('REMOTE_ADDR')) {
1748
        $ipaddress = getenv('REMOTE_ADDR');
1749
    } else {
1750
        $ipaddress = 'UNKNOWN';
1751
    }
1752
1753
    return $ipaddress;
1754
}
1755
1756
/**
1757
 * Escape all HTML, JavaScript, and CSS
1758
 *
1759
 * @param string $input The input string
1760
 * @param string $encoding Which character encoding are we using?
1761
 * @return string
1762
 */
1763
function noHTML($input, $encoding = 'UTF-8')
1764
{
1765
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1766
}
1767
1768
/**
1769
 * handleConfigFile()
1770
 *
1771
 * permits to handle the Teampass config file
1772
 * $action accepts "rebuild" and "update"
1773
 */
1774
function handleConfigFile($action, $field = null, $value = null)
1775
{
1776
    global $server, $user, $pass, $database, $port, $encoding;
1777
    global $SETTINGS;
1778
1779
    $tp_config_file = "../includes/config/tp.config.php";
1780
1781
    // include librairies & connect to DB
1782
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1783
    $pass = defuse_return_decrypted($pass);
1784
    DB::$host = $server;
1785
    DB::$user = $user;
1786
    DB::$password = $pass;
1787
    DB::$dbName = $database;
1788
    DB::$port = $port;
1789
    DB::$encoding = $encoding;
1790
    DB::$error_handler = true;
1791
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1792
    $link->set_charset($encoding);
1793
1794
    if (!file_exists($tp_config_file) || $action == "rebuild") {
1795
        // perform a copy
1796
        if (file_exists($tp_config_file)) {
1797
            if (!copy($tp_config_file, $tp_config_file.'.'.date("Y_m_d_His", time()))) {
1798
                return "ERROR: Could not copy file '".$tp_config_file."'";
1799
            }
1800
        }
1801
1802
        // regenerate
1803
        $data = array();
1804
        $data[0] = "<?php\n";
1805
        $data[1] = "global \$SETTINGS;\n";
1806
        $data[2] = "\$SETTINGS = array (\n";
1807
        $rows = DB::query(
1808
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s",
1809
            "admin"
1810
        );
1811
        foreach ($rows as $record) {
1812
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
1813
        }
1814
        array_push($data, ");\n");
1815
        $data = array_unique($data);
1816
    } elseif ($action == "update" && empty($field) === false) {
1817
        $data = file($tp_config_file);
1818
        $inc = 0;
1819
        $bFound = false;
1820
        foreach ($data as $line) {
1821
            if (stristr($line, ");")) {
1822
                break;
1823
            }
1824
1825
            //
1826
            if (stristr($line, "'".$field."' => '")) {
1827
                $data[$inc] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n";
1828
                $bFound = true;
1829
                break;
1830
            }
1831
            $inc++;
1832
        }
1833
        if ($bFound === false) {
1834
            $data[($inc)] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n);\n";
1835
        }
1836
    }
1837
1838
    // update file
1839
    file_put_contents($tp_config_file, implode('', isset($data) ? $data : array()));
1840
1841
    return true;
1842
}
1843
1844
/*
1845
** Permits to replace &#92; to permit correct display
1846
*/
1847
/**
1848
 * @param string $input
1849
 */
1850
function handleBackslash($input)
1851
{
1852
    return str_replace("&amp;#92;", "&#92;", $input);
1853
}
1854
1855
/*
1856
** Permits to loas settings
1857
*/
1858
function loadSettings()
1859
{
1860
    global $SETTINGS;
1861
1862
    /* LOAD CPASSMAN SETTINGS */
1863
    if (!isset($SETTINGS['loaded']) || $SETTINGS['loaded'] != 1) {
1864
        $SETTINGS['duplicate_folder'] = 0; //by default, this is set to 0;
1865
        $SETTINGS['duplicate_item'] = 0; //by default, this is set to 0;
1866
        $SETTINGS['number_of_used_pw'] = 5; //by default, this value is set to 5;
1867
        $settings = array();
1868
1869
        $rows = DB::query(
1870
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s_type OR type=%s_type2",
1871
            array(
1872
                'type' => "admin",
1873
                'type2' => "settings"
1874
            )
1875
        );
1876
        foreach ($rows as $record) {
1877
            if ($record['type'] == 'admin') {
1878
                $SETTINGS[$record['intitule']] = $record['valeur'];
1879
            } else {
1880
                $settings[$record['intitule']] = $record['valeur'];
1881
            }
1882
        }
1883
        $SETTINGS['loaded'] = 1;
1884
        $SETTINGS['default_session_expiration_time'] = 5;
1885
    }
1886
}
1887
1888
/*
1889
** check if folder has custom fields.
1890
** Ensure that target one also has same custom fields
1891
*/
1892
function checkCFconsistency($source_id, $target_id)
1893
{
1894
    $source_cf = array();
1895
    $rows = DB::QUERY(
1896
        "SELECT id_category
1897
        FROM ".prefix_table("categories_folders")."
1898
        WHERE id_folder = %i",
1899
        $source_id
1900
    );
1901
    foreach ($rows as $record) {
1902
        array_push($source_cf, $record['id_category']);
1903
    }
1904
1905
    $target_cf = array();
1906
    $rows = DB::QUERY(
1907
        "SELECT id_category
1908
        FROM ".prefix_table("categories_folders")."
1909
        WHERE id_folder = %i",
1910
        $target_id
1911
    );
1912
    foreach ($rows as $record) {
1913
        array_push($target_cf, $record['id_category']);
1914
    }
1915
1916
    $cf_diff = array_diff($source_cf, $target_cf);
1917
    if (count($cf_diff) > 0) {
1918
        return false;
1919
    }
1920
1921
    return true;
1922
}
1923
1924
/*
1925
*
1926
*/
1927
function encrypt_or_decrypt_file($filename_to_rework, $filename_status)
1928
{
1929
    global $server, $user, $pass, $database, $port, $encoding;
1930
    global $SETTINGS;
1931
1932
    // Include librairies & connect to DB
1933
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1934
    $pass = defuse_return_decrypted($pass);
1935
    DB::$host = $server;
1936
    DB::$user = $user;
1937
    DB::$password = $pass;
1938
    DB::$dbName = $database;
1939
    DB::$port = $port;
1940
    DB::$encoding = $encoding;
1941
    DB::$error_handler = true;
1942
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1943
    $link->set_charset($encoding);
1944
1945
    // Get file info in DB
1946
    $fileInfo = DB::queryfirstrow(
1947
        "SELECT id FROM ".prefix_table("files")." WHERE file = %s",
1948
        filter_var($filename_to_rework, FILTER_SANITIZE_STRING)
1949
    );
1950
    if (empty($fileInfo['id']) === false) {
1951
        // Load PhpEncryption library
1952
        $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
1953
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
1954
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
1955
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
1956
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
1957
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
1958
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
1959
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
1960
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
1961
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
1962
1963
        // Get KEY
1964
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1965
1966
        if (isset($SETTINGS['enable_attachment_encryption'])
1967
            && $SETTINGS['enable_attachment_encryption'] === "1" &&
1968
            isset($filename_status)
1969
            && ($filename_status === "clear"
1970
                || $filename_status === "0")
1971
        ) {
1972
            // File needs to be encrypted
1973
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1974
                // Make a copy of file
1975
                if (!copy(
1976
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1977
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1978
                )) {
1979
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
1980
                } else {
1981
                    // Do a bck
1982
                    copy(
1983
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1984
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1985
                    );
1986
                }
1987
1988
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1989
1990
                // Now encrypt the file with saltkey
1991
                $err = '';
1992
                try {
1993
                    \Defuse\Crypto\File::encryptFile(
1994
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1995
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1996
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1997
                    );
1998
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1999
                    $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.";
2000
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2001
                    $err = $ex;
2002
                } catch (Defuse\Crypto\Exception\IOException $ex) {
2003
                    $err = $ex;
2004
                }
2005
                if (empty($err) === false) {
2006
                    echo $err;
2007
                }
2008
2009
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
2010
2011
                // update table
2012
                DB::update(
2013
                    prefix_table('files'),
2014
                    array(
2015
                        'status' => 'encrypted'
2016
                        ),
2017
                    "id = %i",
2018
                    $fileInfo['id']
2019
                );
2020
            }
2021
        } elseif (isset($SETTINGS['enable_attachment_encryption'])
2022
            && $SETTINGS['enable_attachment_encryption'] === "0"
2023
            && isset($filename_status)
2024
            && $filename_status === "encrypted"
2025
        ) {
2026
            // file needs to be decrypted
2027
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
2028
                // make a copy of file
2029
                if (!copy(
2030
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2031
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
2032
                )) {
2033
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
2034
                } else {
2035
                    // do a bck
2036
                    copy(
2037
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2038
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
2039
                    );
2040
                }
2041
2042
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
2043
2044
                // Now encrypt the file with saltkey
2045
                $err = '';
2046
                try {
2047
                    \Defuse\Crypto\File::decryptFile(
2048
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
2049
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2050
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2051
                    );
2052
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2053
                    $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.";
2054
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2055
                    $err = $ex;
2056
                } catch (Defuse\Crypto\Exception\IOException $ex) {
2057
                    $err = $ex;
2058
                }
2059
                if (empty($err) === false) {
2060
                    echo $err;
2061
                }
2062
2063
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
2064
2065
                // update table
2066
                DB::update(
2067
                    prefix_table('files'),
2068
                    array(
2069
                        'status' => 'clear'
2070
                        ),
2071
                    "id = %i",
2072
                    $fileInfo['id']
2073
                );
2074
            }
2075
        }
2076
    }
2077
2078
    // Exit
2079
    return false;
2080
}
2081
2082
/**
2083
 * Will encrypte/decrypt a fil eusing Defuse
2084
 * @param  string $type        can be either encrypt or decrypt
2085
 * @param  string $source_file path to source file
2086
 * @param  string $target_file path to target file
2087
 * @return string|boolean
2088
 */
2089
function prepareFileWithDefuse($type, $source_file, $target_file, $password = null)
2090
{
2091
    global $SETTINGS;
2092
2093
    // Load AntiXSS
2094
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2095
    $antiXss = new protect\AntiXSS\AntiXSS();
2096
2097
    // Protect against bad inputs
2098
    if (is_array($source_file) || is_array($target_file)) {
0 ignored issues
show
introduced by
The condition is_array($target_file) is always false.
Loading history...
2099
        return 'error_cannot_be_array';
2100
    }
2101
2102
    // Sanitize
2103
    $source_file = $antiXss->xss_clean($source_file);
2104
    $target_file = $antiXss->xss_clean($target_file);
2105
2106
    // load PhpEncryption library
2107
    $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
2108
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
2109
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
2110
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
2111
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
2112
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
2113
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
2114
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
2115
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
2116
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
2117
2118
    if (empty($password) === true || is_null($password) === true) {
2119
        /*
2120
        File encryption/decryption is done with the SALTKEY
2121
         */
2122
2123
        // get KEY
2124
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2125
2126
        // Now perform action on the file
2127
        $err = '';
2128
        if ($type === 'decrypt') {
2129
            try {
2130
                \Defuse\Crypto\File::decryptFile(
2131
                    $source_file,
2132
                    $target_file,
2133
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2134
                );
2135
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2136
                $err = "decryption_not_possible";
2137
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2138
                $err = $ex;
2139
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2140
                $err = $ex;
2141
            }
2142
        } elseif ($type === 'encrypt') {
2143
            try {
2144
                \Defuse\Crypto\File::encryptFile(
2145
                    $source_file,
2146
                    $target_file,
2147
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2148
                );
2149
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2150
                $err = "encryption_not_possible";
2151
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2152
                $err = $ex;
2153
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2154
                $err = $ex;
2155
            }
2156
        }
2157
    } else {
2158
        /*
2159
        File encryption/decryption is done with special password and not the SALTKEY
2160
         */
2161
2162
        $err = '';
2163
        if ($type === 'decrypt') {
2164
            try {
2165
                \Defuse\Crypto\File::decryptFileWithPassword(
2166
                    $source_file,
2167
                    $target_file,
2168
                    $password
2169
                );
2170
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2171
                $err = "wrong_key";
2172
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2173
                $err = $ex;
2174
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2175
                $err = $ex;
2176
            }
2177
        } elseif ($type === 'encrypt') {
2178
            try {
2179
                \Defuse\Crypto\File::encryptFileWithPassword(
2180
                    $source_file,
2181
                    $target_file,
2182
                    $password
2183
                );
2184
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2185
                $err = "wrong_key";
2186
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2187
                $err = $ex;
2188
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2189
                $err = $ex;
2190
            }
2191
        }
2192
    }
2193
2194
    // return error
2195
    if (empty($err) === false) {
2196
        return $err;
2197
    } else {
2198
        return true;
2199
    }
2200
}
2201
2202
/*
2203
* NOT TO BE USED
2204
*/
2205
function debugTeampass($text)
2206
{
2207
    $debugFile = fopen('D:/wamp64/www/TeamPass/debug.txt', 'r+');
2208
    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

2208
    fputs(/** @scrutinizer ignore-type */ $debugFile, $text);
Loading history...
2209
    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

2209
    fclose(/** @scrutinizer ignore-type */ $debugFile);
Loading history...
2210
}
2211
2212
2213
/**
2214
 * DELETE the file with expected command depending on server type
2215
 * @param  string $file Path to file
2216
 * @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...
2217
 */
2218
function fileDelete($file)
2219
{
2220
    global $SETTINGS;
2221
2222
    // Load AntiXSS
2223
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2224
    $antiXss = new protect\AntiXSS\AntiXSS();
2225
2226
    $file = $antiXss->xss_clean($file);
2227
    if (is_file($file)) {
2228
        unlink($file);
2229
    }
2230
}
2231
2232
/**
2233
 * Permits to extract the file extension
2234
 *
2235
 * @param  string $file File name
2236
 * @return string
2237
 */
2238
function getFileExtension($file)
2239
{
2240
    if (strpos($file, '.') === false) {
2241
        return $file;
2242
    }
2243
2244
    return substr($file, strrpos($file, '.') + 1);
2245
}
2246
2247
/**
2248
 * Permits to clean and sanitize text to be displayed
2249
 * @param  string $text Text to clean
2250
 * @param  string $type What clean to perform
2251
 * @return string
2252
 */
2253
function cleanText($string, $type = null)
2254
{
2255
    global $SETTINGS;
2256
2257
    // Load AntiXSS
2258
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2259
    $antiXss = new protect\AntiXSS\AntiXSS();
2260
2261
    if ($type === "css") {
2262
        // Escape text and quotes in UTF8 format
2263
        return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2264
    } elseif (empty($type) === true || is_null($type) === true || $type === "html") {
2265
        // Html cleaner
2266
        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...
2267
    }
2268
}
2269
2270
/**
2271
 * Performs chmod operation on subfolders
2272
 * @param  string  $dir             Parent folder
2273
 * @param  integer $dirPermissions  New permission on folders
2274
 * @param  integer $filePermissions New permission on files
2275
 * @return boolean
2276
 */
2277
function chmodRecursive($dir, $dirPermissions, $filePermissions)
2278
{
2279
    $pointer_dir = opendir($dir);
2280
    $res = true;
2281
    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

2281
    while ($file = readdir(/** @scrutinizer ignore-type */ $pointer_dir)) {
Loading history...
2282
        if (($file == ".") || ($file == "..")) {
2283
            continue;
2284
        }
2285
2286
        $fullPath = $dir."/".$file;
2287
2288
        if (is_dir($fullPath)) {
2289
            if ($res = @chmod($fullPath, $dirPermissions)) {
2290
                $res = @chmodRecursive($fullPath, $dirPermissions, $filePermissions);
2291
            }
2292
        } else {
2293
            $res = chmod($fullPath, $filePermissions);
2294
        }
2295
        if (!$res) {
2296
            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

2296
            closedir(/** @scrutinizer ignore-type */ $pointer_dir);
Loading history...
2297
            return false;
2298
        }
2299
    }
2300
    closedir($pointer_dir);
2301
    if (is_dir($dir) && $res) {
2302
        $res = @chmod($dir, $dirPermissions);
2303
    }
2304
2305
    return $res;
2306
}
2307
2308
/**
2309
 * Check if user can access to this item
2310
 * @param integer $item_id ID of item
2311
 */
2312
function accessToItemIsGranted($item_id)
2313
{
2314
    global $SETTINGS;
2315
2316
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2317
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2318
2319
    // Prepare superGlobal variables
2320
    $session_groupes_visibles = $superGlobal->get("groupes_visibles", "SESSION");
2321
    $session_list_restricted_folders_for_items = $superGlobal->get("list_restricted_folders_for_items", "SESSION");
2322
2323
    // Load item data
2324
    $data = DB::queryFirstRow(
2325
        "SELECT id_tree
2326
        FROM ".prefix_table("items")."
2327
        WHERE id = %i",
2328
        $item_id
2329
    );
2330
2331
    // Check if user can access this folder
2332
    if (in_array($data['id_tree'], $session_groupes_visibles) === false) {
2333
        // Now check if this folder is restricted to user
2334
        if (isset($session_list_restricted_folders_for_items[$data['id_tree']])
2335
            && !in_array($item_id, $session_list_restricted_folders_for_items[$data['id_tree']])
2336
        ) {
2337
            return "ERR_FOLDER_NOT_ALLOWED";
2338
        } else {
2339
            return "ERR_FOLDER_NOT_ALLOWED";
2340
        }
2341
    }
2342
2343
    return true;
2344
}
2345
2346
/**
2347
 * Creates a unique key
2348
 * @lenght  integer $lenght Key lenght
2349
 * @return string
2350
 */
2351
function uniqidReal($lenght = 13)
2352
{
2353
    // uniqid gives 13 chars, but you could adjust it to your needs.
2354
    if (function_exists("random_bytes")) {
2355
        $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

2355
        $bytes = random_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2356
    } elseif (function_exists("openssl_random_pseudo_bytes")) {
2357
        $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

2357
        $bytes = openssl_random_pseudo_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2358
    } else {
2359
        throw new Exception("no cryptographically secure random function available");
2360
    }
2361
    return substr(bin2hex($bytes), 0, $lenght);
2362
}
2363
2364
/**
2365
 * Obfuscate an email address
2366
 *
2367
 * @param string $email Email address
2368
 *
2369
 * @return string
2370
 */
2371
function obfuscateEmail($email)
2372
{
2373
    $prop = 2;
2374
    $start = '';
2375
    $end = '';
2376
    $domain = substr(strrchr($email, "@"), 1);
2377
    $mailname = str_replace($domain, '', $email);
2378
    $name_l = strlen($mailname);
2379
    $domain_l = strlen($domain);
2380
    for ($i = 0; $i <= $name_l / $prop - 1; $i++) {
2381
        $start .= 'x';
2382
    }
2383
2384
    for ($i = 0; $i <= $domain_l / $prop - 1; $i++) {
2385
        $end .= 'x';
2386
    }
2387
2388
    return substr_replace($mailname, $start, 2, $name_l / $prop)
2389
        .substr_replace($domain, $end, 2, $domain_l / $prop);
2390
}
2391
2392
/**
2393
 * Permits to get LDAP information about a user
2394
 *
2395
 * @param string $username User name
2396
 * @param string $password User password
2397
 * @param array  $SETTINGS Settings
2398
 *
2399
 * @return string
2400
 */
2401
function connectLDAP($username, $password, $SETTINGS)
2402
{
2403
    $ldapInfo = '';
2404
2405
    // Prepare LDAP connection if set up
2406
    
2407
    if ($SETTINGS['ldap_type'] === 'posix-search') {
2408
        $ldapInfo = ldapPosixSearch(
2409
            $username,
2410
            $password,
2411
            $SETTINGS
2412
        );
2413
    } else {
2414
        $ldapInfo = ldapPosixAndWindows(
2415
            $username,
2416
            $password,
2417
            $SETTINGS
2418
        );
2419
    }
2420
2421
    return json_encode($ldapInfo);
2422
}
2423
2424
2425
/**
2426
 * Undocumented function
2427
 *
2428
 * @param string $username Username
2429
 * @param string $password Password
2430
 * @param array  $SETTINGS Settings
2431
 *
2432
 * @return array
2433
 */
2434
function ldapPosixSearch($username, $password, $SETTINGS)
2435
{
2436
    $ldapURIs = '';
2437
    $user_email = '';
2438
    $user_found = false;
2439
    $user_lastname = '';
2440
    $user_name = '';
2441
    $ldapConnection = false;
2442
2443
    foreach (explode(",", $SETTINGS['ldap_domain_controler']) as $domainControler) {
2444
        if ($SETTINGS['ldap_ssl'] == 1) {
2445
            $ldapURIs .= "ldaps://".$domainControler.":".$SETTINGS['ldap_port']." ";
2446
        } else {
2447
            $ldapURIs .= "ldap://".$domainControler.":".$SETTINGS['ldap_port']." ";
2448
        }
2449
    }
2450
    $ldapconn = ldap_connect($ldapURIs);
2451
2452
    if ($SETTINGS['ldap_tls']) {
2453
        ldap_start_tls($ldapconn);
2454
    }
2455
    ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
2456
    ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
2457
2458
    // Is LDAP connection ready?
2459
    if ($ldapconn !== false) {
2460
        // Should we bind the connection?
2461
        if (empty($SETTINGS['ldap_bind_dn']) === false
2462
            && empty($SETTINGS['ldap_bind_passwd']) === false
2463
        ) {
2464
            $ldapbind = ldap_bind($ldapconn, $SETTINGS['ldap_bind_dn'], $SETTINGS['ldap_bind_passwd']);
2465
        } else {
2466
            $ldapbind = false;
2467
        }
2468
        if ((empty($SETTINGS['ldap_bind_dn']) === true && empty($SETTINGS['ldap_bind_passwd']) === true)
2469
            || $ldapbind === true
2470
        ) {
2471
            $filter = "(&(".$SETTINGS['ldap_user_attribute']."=".$username.")(objectClass=".$SETTINGS['ldap_object_class']."))";
2472
            $result = ldap_search(
2473
                $ldapconn,
2474
                $SETTINGS['ldap_search_base'],
2475
                $filter,
2476
                array('dn', 'mail', 'givenname', 'sn', 'samaccountname')
2477
            );
2478
2479
            // Check if user was found in AD
2480
            if (ldap_count_entries($ldapconn, $result) > 0) {
2481
                // Get user's info and especially the DN
2482
                $result = ldap_get_entries($ldapconn, $result);
2483
                $user_dn = $result[0]['dn'];
2484
                $user_email = $result[0]['mail'][0];
2485
                $user_lastname = $result[0]['sn'][0];
2486
                $user_name = isset($result[0]['givenname'][0]) === true ? $result[0]['givenname'][0] : '';
2487
                $user_found = true;
2488
2489
                // Should we restrain the search in specified user groups
2490
                $GroupRestrictionEnabled = false;
2491
                if (isset($SETTINGS['ldap_usergroup']) === true
2492
                    && empty($SETTINGS['ldap_usergroup']) === false
2493
                ) {
2494
                    // New way to check User's group membership
2495
                    $filter_group = "memberUid=".$username;
2496
                    $result_group = ldap_search(
2497
                        $ldapconn,
2498
                        $SETTINGS['ldap_search_base'],
2499
                        $filter_group,
2500
                        array('dn', 'samaccountname')
2501
                    );
2502
2503
                    if ($result_group) {
0 ignored issues
show
introduced by
$result_group is of type resource, thus it always evaluated to false.
Loading history...
2504
                        $entries = ldap_get_entries($ldapconn, $result_group);
2505
2506
                        if ($entries['count'] > 0) {
2507
                            // Now check if group fits
2508
                            for ($i = 0; $i < $entries['count']; $i++) {
2509
                                $parsr = ldap_explode_dn($entries[$i]['dn'], 0);
2510
                                if (str_replace(array('CN=', 'cn='), '', $parsr[0]) === $SETTINGS['ldap_usergroup']) {
2511
                                    $GroupRestrictionEnabled = true;
2512
                                    break;
2513
                                }
2514
                            }
2515
                        }
2516
                    }
2517
                }
2518
2519
                // Is user in the LDAP?
2520
                if ($GroupRestrictionEnabled === true
2521
                    || ($GroupRestrictionEnabled === false
2522
                    && (isset($SETTINGS['ldap_usergroup']) === false
2523
                    || (isset($SETTINGS['ldap_usergroup']) === true
2524
                    && empty($SETTINGS['ldap_usergroup']) === true)))
2525
                ) {
2526
                    // Try to auth inside LDAP
2527
                    $ldapbind = ldap_bind($ldapconn, $user_dn, $password);
2528
                    if ($ldapbind === true) {
2529
                        $ldapConnection = true;
2530
                    } else {
2531
                        $ldapConnection = false;
2532
                    }
2533
                }
2534
            } else {
2535
                $ldapConnection = false;
2536
            }
2537
        } else {
2538
            $ldapConnection = false;
2539
        }
2540
    } else {
2541
        $ldapConnection = false;
2542
    }
2543
2544
    return array(
2545
        'lastname' => $user_lastname,
2546
        'name' => $user_name,
2547
        'email' => $user_email,
2548
        'auth_success' => $ldapConnection,
2549
        'user_found' => $user_found
2550
    );
2551
}
2552
2553
/**
2554
 * Undocumented function
2555
 *
2556
 * @param string $username Username
2557
 * @param string $password Password
2558
 * @param array  $SETTINGS Settings
2559
 *
2560
 * @return array
2561
 */
2562
function ldapPosixAndWindows($username, $password, $SETTINGS)
2563
{
2564
    $user_email = '';
2565
    $user_found = false;
2566
    $user_lastname = '';
2567
    $user_name = '';
2568
    $ldapConnection = false;
2569
    $ldap_suffix = '';
2570
2571
    //Multiple Domain Names
2572
    if (strpos(html_entity_decode($username), '\\') === true) {
2573
        $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...
2574
        $username = substr(html_entity_decode($username), strpos(html_entity_decode($username), '\\') + 1);
2575
    }
2576
    
2577
    $adldap = new SplClassLoader('adLDAP', '../includes/libraries/LDAP');
2578
    $adldap->register();
2579
2580
    // Posix style LDAP handles user searches a bit differently
2581
    if ($SETTINGS['ldap_type'] === 'posix') {
2582
        $ldap_suffix = ','.$SETTINGS['ldap_suffix'].','.$SETTINGS['ldap_domain_dn'];
2583
    } else {
2584
        // case where $SETTINGS['ldap_type'] equals 'windows'
2585
        //Multiple Domain Names
2586
        $ldap_suffix = $SETTINGS['ldap_suffix'];
2587
    }
2588
2589
    // Ensure no double commas exist in ldap_suffix
2590
    $ldap_suffix = str_replace(',,', ',', $ldap_suffix);
2591
2592
    // Create LDAP connection
2593
    $adldap = new adLDAP\adLDAP(
2594
        array(
2595
            'base_dn' => $SETTINGS['ldap_domain_dn'],
2596
            'account_suffix' => $ldap_suffix,
2597
            'domain_controllers' => explode(",", $SETTINGS['ldap_domain_controler']),
2598
            'ad_port' => $SETTINGS['ldap_port'],
2599
            'use_ssl' => $SETTINGS['ldap_ssl'],
2600
            'use_tls' => $SETTINGS['ldap_tls']
2601
        )
2602
    );
2603
2604
    // OpenLDAP expects an attribute=value pair
2605
    if ($SETTINGS['ldap_type'] === 'posix') {
2606
        $auth_username = $SETTINGS['ldap_user_attribute'].'='.$username;
2607
    } else {
2608
        $auth_username = $username;
2609
    }
2610
2611
    // Authenticate the user
2612
    if ($adldap->authenticate($auth_username, html_entity_decode($password))) {
2613
        // Get user info
2614
        $result = $adldap->user()->info($auth_username, array('mail', 'givenname', 'sn'));
2615
        $user_email = $result[0]['mail'][0];
2616
        $user_lastname = $result[0]['sn'][0];
2617
        $user_name = $result[0]['givenname'][0];
2618
        $user_found = true;
2619
2620
        // Is user in allowed group
2621
        if (isset($SETTINGS['ldap_allowed_usergroup']) === true
2622
            && empty($SETTINGS['ldap_allowed_usergroup']) === false
2623
        ) {
2624
            if ($adldap->user()->inGroup($auth_username, $SETTINGS['ldap_allowed_usergroup']) === true) {
2625
                $ldapConnection = true;
2626
            } else {
2627
                $ldapConnection = false;
2628
            }
2629
        } else {
2630
            $ldapConnection = true;
2631
        }
2632
    } else {
2633
        $ldapConnection = false;
2634
    }
2635
2636
    return array(
2637
        'lastname' => $user_lastname,
2638
        'name' => $user_name,
2639
        'email' => $user_email,
2640
        'auth_success' => $ldapConnection,
2641
        'user_found' => $user_found
2642
    );
2643
}
2644