Completed
Push — development ( f2581b...1d4607 )
by Nils
07:30
created

main.functions.php ➔ bCrypt()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 2
nop 2
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * @file          main.functions.php
5
 * @author        Nils Laumaillé
6
 * @version       2.1.27
7
 * @copyright     (c) 2009-2017 Nils Laumaillé
8
 * @licensing     GNU AFFERO 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
20 View Code Duplication
if (file_exists('../includes/config/tp.config.php')) {
21
    require_once '../includes/config/tp.config.php';
22
} elseif (file_exists('./includes/config/tp.config.php')) {
23
    require_once './includes/config/tp.config.php';
24
} elseif (file_exists('../../includes/config/tp.config.php')) {
25
    require_once '../../includes/config/tp.config.php';
26
} else {
27
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
28
}
29
30
// load phpCrypt
31
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
32
    require_once '../includes/libraries/phpcrypt/phpCrypt.php';
33
    require_once '../includes/config/settings.php';
34
} else {
35
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/phpcrypt/phpCrypt.php';
36
    require_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
37
}
38
39
// Prepare PHPCrypt class calls
40
use PHP_Crypt\PHP_Crypt as PHP_Crypt;
41
42
// Prepare Encryption class calls
43
use \Defuse\Crypto\Crypto;
44
use \Defuse\Crypto\Exception as Ex;
45
46
//Generate N# of random bits for use as salt
47
/**
48
 * @param integer $size
49
 */
50
function getBits($size)
51
{
52
    $str = '';
53
    $var_x = $size + 10;
54
    for ($var_i = 0; $var_i < $var_x; $var_i++) {
55
        $str .= base_convert(mt_rand(1, 36), 10, 36);
56
    }
57
    return substr($str, 0, $size);
58
}
59
60
//generate pbkdf2 compliant hash
61 View Code Duplication
function strHashPbkdf2($var_p, $var_s, $var_c, $var_kl, $var_a = 'sha256', $var_st = 0)
0 ignored issues
show
Duplication introduced by
This function seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
62
{
63
    $var_kb = $var_st + $var_kl; // Key blocks to compute
64
    $var_dk = ''; // Derived key
65
66
    for ($block = 1; $block <= $var_kb; $block++) { // Create key
67
        $var_ib = $var_h = hash_hmac($var_a, $var_s.pack('N', $block), $var_p, true); // Initial hash for this block
68
        for ($var_i = 1; $var_i < $var_c; $var_i++) { // Perform block iterations
69
            $var_ib ^= ($var_h = hash_hmac($var_a, $var_h, $var_p, true)); // XOR each iterate
70
        }
71
        $var_dk .= $var_ib; // Append iterated block
72
    }
73
    return substr($var_dk, $var_st, $var_kl); // Return derived key of correct length
74
}
75
76
/**
77
 * stringUtf8Decode()
78
 *
79
 * utf8_decode
80
 */
81
function stringUtf8Decode($string)
82
{
83
    return str_replace(" ", "+", utf8_decode($string));
84
}
85
86
/**
87
 * encryptOld()
88
 *
89
 * crypt a string
90
 * @param string $text
91
 */
92
function encryptOld($text, $personalSalt = "")
93
{
94
    if (empty($personalSalt) === false) {
95
        return trim(
96
            base64_encode(
97
                mcrypt_encrypt(
98
                    MCRYPT_RIJNDAEL_256,
99
                    $personalSalt,
100
                    $text,
101
                    MCRYPT_MODE_ECB,
102
                    mcrypt_create_iv(
103
                        mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
104
                        MCRYPT_RAND
105
                    )
106
                )
107
            )
108
        );
109
    }
110
111
    // If $personalSalt is not empty
112
    return trim(
113
        base64_encode(
114
            mcrypt_encrypt(
115
                MCRYPT_RIJNDAEL_256,
116
                SALT,
117
                $text,
118
                MCRYPT_MODE_ECB,
119
                mcrypt_create_iv(
120
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
121
                    MCRYPT_RAND
122
                )
123
            )
124
        )
125
    );
126
}
127
128
/**
129
 * decryptOld()
130
 *
131
 * decrypt a crypted string
132
 */
133
function decryptOld($text, $personalSalt = "")
134
{
135
    if (!empty($personalSalt)) {
136
        return trim(
137
            mcrypt_decrypt(
138
                MCRYPT_RIJNDAEL_256,
139
                $personalSalt,
140
                base64_decode($text),
141
                MCRYPT_MODE_ECB,
142
                mcrypt_create_iv(
143
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
144
                    MCRYPT_RAND
145
                )
146
            )
147
        );
148
    }
149
150
    // No personal SK
151
    return trim(
152
        mcrypt_decrypt(
153
            MCRYPT_RIJNDAEL_256,
154
            SALT,
155
            base64_decode($text),
156
            MCRYPT_MODE_ECB,
157
            mcrypt_create_iv(
158
                mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
159
                MCRYPT_RAND
160
            )
161
        )
162
    );
163
}
164
165
/**
166
 * encrypt()
167
 *
168
 * crypt a string
169
 * @param string $decrypted
170
 */
171
function encrypt($decrypted, $personalSalt = "")
172
{
173
    global $SETTINGS;
174
175 View Code Duplication
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
176
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
177
    } else {
178
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
179
    }
180
181
    if (!empty($personalSalt)) {
182
        $staticSalt = $personalSalt;
183
    } else {
184
        $staticSalt = SALT;
185
    }
186
187
    //set our salt to a variable
188
    // Get 64 random bits for the salt for pbkdf2
189
    $pbkdf2Salt = getBits(64);
190
    // generate a pbkdf2 key to use for the encryption.
191
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
192
    // Build $init_vect and $ivBase64.  We use a block size of 256 bits (AES compliant)
193
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
194
    $init_vect = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);
195
196
    //base64 trim
197
    if (strlen($ivBase64 = rtrim(base64_encode($init_vect), '=')) != 43) {
198
        return false;
199
    }
200
    // Encrypt $decrypted
201
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $init_vect);
202
    // MAC the encrypted text
203
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
204
    // We're done!
205
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
206
}
207
208
/**
209
 * decrypt()
210
 *
211
 * decrypt a crypted string
212
 */
213
function decrypt($encrypted, $personalSalt = "")
214
{
215
    global $SETTINGS;
216
217 View Code Duplication
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
218
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
219
    } else {
220
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
221
    }
222
223
    if (!empty($personalSalt)) {
224
        $staticSalt = $personalSalt;
225
    } else {
226
        $staticSalt = file_get_contents(SECUREPATH."/teampass-seckey.txt");
227
    }
228
    //base64 decode the entire payload
229
    $encrypted = base64_decode($encrypted);
230
    // get the salt
231
    $pbkdf2Salt = substr($encrypted, -64);
232
    //remove the salt from the string
233
    $encrypted = substr($encrypted, 0, -64);
234
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
235
    // Retrieve $init_vect which is the first 22 characters plus ==, base64_decoded.
236
    $init_vect = base64_decode(substr($encrypted, 0, 43).'==');
237
    // Remove $init_vect from $encrypted.
238
    $encrypted = substr($encrypted, 43);
239
    // Retrieve $mac which is the last 64 characters of $encrypted.
240
    $mac = substr($encrypted, -64);
241
    // Remove the last 64 chars from encrypted (remove MAC)
242
    $encrypted = substr($encrypted, 0, -64);
243
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
244
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
245
        return false;
246
    }
247
    // Decrypt the data.
248
    $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $init_vect), "\0\4");
249
    // Yay!
250
    return $decrypted;
251
}
252
253
254
/**
255
 * genHash()
256
 *
257
 * Generate a hash for user login
258
 * @param string $password
259
 */
260
function bCrypt($password, $cost)
261
{
262
    $salt = sprintf('$2y$%02d$', $cost);
263
    if (function_exists('openssl_random_pseudo_bytes')) {
264
        $salt .= bin2hex(openssl_random_pseudo_bytes(11));
265
    } else {
266
        $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
267
        for ($i = 0; $i < 22; $i++) {
268
            $salt .= $chars[mt_rand(0, 63)];
269
        }
270
    }
271
    return crypt($password, $salt);
272
}
273
274
function cryption_before_defuse($message, $saltkey, $init_vect, $type = null, $scope = "public")
275
{
276
    if (DEFUSE_ENCRYPTION === true) {
277
        if ($scope === "perso") {
278
            return defuse_crypto(
279
                $message,
280
                $saltkey,
281
                $type
282
            );
283
        } else {
284
            return defuse_crypto(
285
                $message,
286
                file_get_contents(SECUREPATH."/teampass-seckey.txt"),
287
                $type
288
            );
289
        }
290
    } else {
291
        return cryption_phpCrypt($message, $saltkey, $init_vect, $type);
292
    }
293
}
294
295
/*
296
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
297
 *
298
 * Using AES_128 and mode CBC
299
 *
300
 * $key and $init_vect have to be given in hex format
301
 */
302
function cryption_phpCrypt($string, $key, $init_vect, $type)
303
{
304
    // manage key origin
305
    if (null != SALT && $key != SALT) {
306
        // check key (AES-128 requires a 16 bytes length key)
307
        if (strlen($key) < 16) {
308
            for ($inc = strlen($key) + 1; $inc <= 16; $inc++) {
309
                $key .= chr(0);
310
            }
311
        } elseif (strlen($key) > 16) {
312
            $key = substr($key, 16);
313
        }
314
    }
315
316
    // load crypt
317
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
318
319
    if ($type == "encrypt") {
320
        // generate IV and encrypt
321
        $init_vect = $crypt->createIV();
322
        $encrypt = $crypt->encrypt($string);
323
        // return
324
        return array(
325
            "string" => bin2hex($encrypt),
326
            "iv" => bin2hex($init_vect),
327
            "error" => empty($encrypt) ? "ERR_ENCRYPTION_NOT_CORRECT" : ""
328
        );
329
    } elseif ($type == "decrypt") {
330
        // case if IV is empty
331
        if (empty($init_vect)) {
332
                    return array(
333
                'string' => "",
334
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
335
            );
336
        }
337
338
        // convert
339
        try {
340
            $string = testHex2Bin(trim($string));
341
            $init_vect = testHex2Bin($init_vect);
342
        } catch (Exception $e) {
343
            return array(
344
                'string' => "",
345
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
346
            );
347
        }
348
349
        // load IV
350
        $crypt->IV($init_vect);
351
        // decrypt
352
        $decrypt = $crypt->decrypt($string);
353
        // return
354
        return array(
355
            'string' => str_replace(chr(0), "", $decrypt),
356
            'error' => ""
357
        );
358
    }
359
}
360
361
function testHex2Bin($val)
362
{
363
    if (!@hex2bin($val)) {
364
        throw new Exception("ERROR");
365
    }
366
    return hex2bin($val);
367
}
368
369
/**
370
 * @param string $ascii_key
371
 * @param string $type
372
 */
373
function cryption($message, $ascii_key, $type) //defuse_crypto
374
{
375
    global $SETTINGS;
376
377
    // load PhpEncryption library
378 View Code Duplication
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
379
        $path = '../includes/libraries/Encryption/Encryption/';
380
    } else {
381
        $path = $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
382
    }
383
384
    require_once $path.'Crypto.php';
385
    require_once $path.'Encoding.php';
386
    require_once $path.'DerivedKeys.php';
387
    require_once $path.'Key.php';
388
    require_once $path.'KeyOrPassword.php';
389
    require_once $path.'File.php';
390
    require_once $path.'RuntimeTests.php';
391
    require_once $path.'KeyProtectedByPassword.php';
392
    require_once $path.'Core.php';
393
394
    // init
395
    $err = '';
396
    if (empty($ascii_key)) {
397
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
398
    }
399
400
    // convert KEY
401
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
402
403
    try {
404
        if ($type === "encrypt") {
405
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
406
        } elseif ($type === "decrypt") {
407
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
408
        }
409
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
410
        $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.";
411
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
412
        $err = $ex;
413
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
414
        $err = $ex;
415
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
416
        $err = $ex;
417
    } catch (Defuse\Crypto\Exception\IOException $ex) {
418
        $err = $ex;
419
    }
420
421
    return array(
422
        'string' => isset($text) ? $text : "",
423
        'error' => $err
424
    );
425
}
426
427
function defuse_generate_key()
428
{
429
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
430
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
431
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
432
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
433
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
434
    require_once '../includes/libraries/Encryption/Encryption/File.php';
435
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
436
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
437
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
438
439
    $key = \Defuse\Crypto\Key::createNewRandomKey();
440
    $key = $key->saveToAsciiSafeString();
441
    return $key;
442
}
443
444
function defuse_generate_personal_key($psk)
445
{
446
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
447
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
448
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
449
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
450
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
451
    require_once '../includes/libraries/Encryption/Encryption/File.php';
452
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
453
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
454
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
455
456
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
457
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
458
459
    return $protected_key_encoded; // save this in user table
460
}
461
462
/**
463
 * @param string $psk
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
 * @param  [type] $value Encrypted string
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
493
 * @return [type]        Decrypted string
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
494
 */
495
function defuse_return_decrypted($value)
496
{
497
    if (substr($value, 0, 3) === "def") {
498
        $value = cryption($value, "", "decrypt")['string'];
499
    }
500
    return $value;
501
}
502
503
/**
504
 * trimElement()
505
 *
506
 * trim a string depending on a specific string
507
 * @param string $element
508
 * @return string
509
 */
510
function trimElement($chaine, $element)
511
{
512
    if (!empty($chaine)) {
513
        if (is_array($chaine) === true) {
514
            $chaine = implode(";", $chaine);
515
        }
516
        $chaine = trim($chaine);
517
        if (substr($chaine, 0, 1) == $element) {
518
            $chaine = substr($chaine, 1);
519
        }
520
        if (substr($chaine, strlen($chaine) - 1, 1) == $element) {
521
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
522
        }
523
    }
524
    return $chaine;
525
}
526
527
/**
528
 * cleanString()
529
 *
530
 * permits to suppress all "special" characters from string
531
 */
532
function cleanString($string, $special = false)
533
{
534
    // Create temporary table for special characters escape
535
    $tabSpecialChar = array();
536
    for ($i = 0; $i <= 31; $i++) {
537
        $tabSpecialChar[] = chr($i);
538
    }
539
    array_push($tabSpecialChar, "<br />");
540
    if ($special == "1") {
541
        $tabSpecialChar = array_merge($tabSpecialChar, array("</li>", "<ul>", "<ol>"));
542
    }
543
544
    return str_replace($tabSpecialChar, "\n", $string);
545
}
546
547
function db_error_handler($params)
548
{
549
    echo "Error: ".$params['error']."<br>\n";
550
    echo "Query: ".$params['query']."<br>\n";
551
    throw new Exception("Error - Query", 1);
552
}
553
554
/**
555
 * [identifyUserRights description]
556
 * @param  string $groupesVisiblesUser  [description]
557
 * @param  string $groupesInterditsUser [description]
558
 * @param  string $isAdmin              [description]
559
 * @param  string $idFonctions          [description]
560
 * @return string                       [description]
561
 */
562
function identifyUserRights($groupesVisiblesUser, $groupesInterditsUser, $isAdmin, $idFonctions)
563
{
564
    global $server, $user, $pass, $database, $port, $encoding;
565
    global $SETTINGS;
566
567
    //load ClassLoader
568
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
569
570
    //Connect to DB
571
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
572
    $pass = defuse_return_decrypted($pass);
573
    DB::$host = $server;
574
    DB::$user = $user;
575
    DB::$password = $pass;
576
    DB::$dbName = $database;
577
    DB::$port = $port;
578
    DB::$encoding = $encoding;
579
    DB::$error_handler = true;
580
    $link = mysqli_connect($server, $user, $pass, $database, $port);
581
    $link->set_charset($encoding);
582
583
    //Build tree
584
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
585
    $tree->register();
586
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
587
588
    // Check if user is ADMINISTRATOR
589
    if ($isAdmin == 1) {
590
        $groupesVisibles = array();
591
        $_SESSION['personal_folders'] = array();
592
        $_SESSION['groupes_visibles'] = array();
593
        $_SESSION['groupes_interdits'] = array();
594
        $_SESSION['personal_visible_groups'] = array();
595
        $_SESSION['read_only_folders'] = array();
596
        $_SESSION['list_restricted_folders_for_items'] = array();
597
        $_SESSION['list_folders_editable_by_role'] = array();
598
        $_SESSION['list_folders_limited'] = array();
599
        $_SESSION['groupes_visibles_list'] = "";
600
        $_SESSION['list_folders_limited'] = "";
601
        $rows = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i", 0);
602
        foreach ($rows as $record) {
603
            array_push($groupesVisibles, $record['id']);
604
        }
605
        $_SESSION['groupes_visibles'] = $groupesVisibles;
606
        $_SESSION['all_non_personal_folders'] = $groupesVisibles;
607
        // Exclude all PF
608
        $_SESSION['forbiden_pfs'] = array();
609
        $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
610
        $where->add('personal_folder=%i', 1);
611
        if (isset($SETTINGS['enable_pf_feature']) && $SETTINGS['enable_pf_feature'] == 1) {
612
            $where->add('title=%s', $_SESSION['user_id']);
613
            $where->negateLast();
614
        }
615
        // Get ID of personal folder
616
        $persfld = DB::queryfirstrow(
617
            "SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s",
618
            $_SESSION['user_id']
619
        );
620
        if (!empty($persfld['id'])) {
621
            if (!in_array($persfld['id'], $_SESSION['groupes_visibles'])) {
622
                array_push($_SESSION['groupes_visibles'], $persfld['id']);
623
                array_push($_SESSION['personal_visible_groups'], $persfld['id']);
624
                // get all descendants
625
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
626
                $tree->rebuild();
627
                $tst = $tree->getDescendants($persfld['id']);
628
                foreach ($tst as $t) {
629
                    array_push($_SESSION['groupes_visibles'], $t->id);
630
                    array_push($_SESSION['personal_visible_groups'], $t->id);
631
                }
632
            }
633
        }
634
635
        // get complete list of ROLES
636
        $tmp = explode(";", $idFonctions);
637
        $rows = DB::query(
638
            "SELECT * FROM ".prefix_table("roles_title")."
639
            ORDER BY title ASC"
640
        );
641
        foreach ($rows as $record) {
642
            if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
643
                array_push($tmp, $record['id']);
644
            }
645
        }
646
        $_SESSION['fonction_id'] = implode(";", $tmp);
647
648
        $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
649
        $_SESSION['is_admin'] = $isAdmin;
650
        // Check if admin has created Folders and Roles
651
        DB::query("SELECT * FROM ".prefix_table("nested_tree")."");
652
        $_SESSION['nb_folders'] = DB::count();
653
        DB::query("SELECT * FROM ".prefix_table("roles_title"));
654
        $_SESSION['nb_roles'] = DB::count();
655
    } else {
656
        // init
657
        $_SESSION['groupes_visibles'] = array();
658
        $_SESSION['personal_folders'] = array();
659
        $_SESSION['groupes_interdits'] = array();
660
        $_SESSION['personal_visible_groups'] = array();
661
        $_SESSION['read_only_folders'] = array();
662
        $_SESSION['fonction_id'] = $idFonctions;
663
        $groupesInterdits = array();
664
        if (is_array($groupesInterditsUser) === false) {
665
            $groupesInterditsUser = explode(';', trimElement($groupesInterditsUser, ";"));
666
        }
667
        if (!empty($groupesInterditsUser) && count($groupesInterditsUser) > 0) {
668
            $groupesInterdits = $groupesInterditsUser;
669
        }
670
        $_SESSION['is_admin'] = $isAdmin;
671
        $fonctionsAssociees = explode(';', trimElement($idFonctions, ";"));
672
673
        $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
674
675
        // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
676
        foreach ($fonctionsAssociees as $roleId) {
677
            if (!empty($roleId)) {
678
                // Get allowed folders for each Role
679
                $rows = DB::query("SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id=%i", $roleId);
680
681
                if (DB::count() > 0) {
682
                    $tmp = DB::queryfirstrow("SELECT allow_pw_change FROM ".prefix_table("roles_title")." WHERE id = %i", $roleId);
683
                    foreach ($rows as $record) {
684
                        if (isset($record['folder_id']) && !in_array($record['folder_id'], $listAllowedFolders)) {
685
                            array_push($listAllowedFolders, $record['folder_id']);
686
                        }
687
                        // Check if this group is allowed to modify any pw in allowed folders
688
                        if ($tmp['allow_pw_change'] == 1 && !in_array($record['folder_id'], $listFoldersEditableByRole)) {
689
                            array_push($listFoldersEditableByRole, $record['folder_id']);
690
                        }
691
                    }
692
                    // Check for the users roles if some specific rights exist on items
693
                    $rows = DB::query(
694
                        "SELECT i.id_tree, r.item_id
695
                        FROM ".prefix_table("items")." as i
696
                        INNER JOIN ".prefix_table("restriction_to_roles")." as r ON (r.item_id=i.id)
697
                        WHERE r.role_id=%i
698
                        ORDER BY i.id_tree ASC",
699
                        $roleId
700
                    );
701
                    $inc = 0;
702
                    foreach ($rows as $record) {
703
                        if (isset($record['id_tree'])) {
704
                            $listFoldersLimited[$record['id_tree']][$inc] = $record['item_id'];
705
                            $inc++;
706
                        }
707
                    }
708
                }
709
            }
710
        }
711
712
        // Does this user is allowed to see other items
713
        $inc = 0;
714
        $rows = DB::query(
715
            "SELECT id, id_tree FROM ".prefix_table("items")."
716
            WHERE restricted_to LIKE %ss AND inactif=%s",
717
            $_SESSION['user_id'].';',
718
            '0'
719
        );
720
        foreach ($rows as $record) {
721
            $listRestrictedFoldersForItems[$record['id_tree']][$inc] = $record['id'];
722
            $inc++;
723
        }
724
        // => Build final lists
725
        // Clean arrays
726
        $listAllowedFolders = array_unique($listAllowedFolders);
727
        $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ";"));
728
        // Add user allowed folders
729
        $allowedFoldersTmp = array_unique(
730
            array_merge($listAllowedFolders, $groupesVisiblesUser)
731
        );
732
        // Exclude from allowed folders all the specific user forbidden folders
733
        $allowedFolders = array();
734
        foreach ($allowedFoldersTmp as $ident) {
735
            if (!in_array($ident, $groupesInterditsUser) && !empty($ident)) {
736
                array_push($allowedFolders, $ident);
737
            }
738
        }
739
740
        // Clean array
741
        $listAllowedFolders = array_filter(array_unique($allowedFolders));
742
743
        // Exclude all PF
744
        $_SESSION['forbiden_pfs'] = array();
745
746
        $where = new WhereClause('and');
747
        $where->add('personal_folder=%i', 1);
748
        if (isset($SETTINGS['enable_pf_feature']) &&
749
            $SETTINGS['enable_pf_feature'] == 1 &&
750
            isset($_SESSION['personal_folder']) &&
751
            $_SESSION['personal_folder'] == 1
752
        ) {
753
            $where->add('title=%s', $_SESSION['user_id']);
754
            $where->negateLast();
755
        }
756
757
        $persoFlds = DB::query(
758
            "SELECT id
759
            FROM ".prefix_table("nested_tree")."
760
            WHERE %l",
761
            $where
762
        );
763
        foreach ($persoFlds as $persoFldId) {
764
            array_push($_SESSION['forbiden_pfs'], $persoFldId['id']);
765
        }
766
        // Get IDs of personal folders
767
        if (isset($SETTINGS['enable_pf_feature']) &&
768
            $SETTINGS['enable_pf_feature'] == 1 &&
769
            isset($_SESSION['personal_folder']) &&
770
            $_SESSION['personal_folder'] == 1
771
        ) {
772
            $persoFld = DB::queryfirstrow(
773
                "SELECT id
774
                FROM ".prefix_table("nested_tree")."
775
                WHERE title = %s",
776
                $_SESSION['user_id']
777
            );
778
            if (empty($persoFld['id']) === false) {
779
                if (!in_array($persoFld['id'], $listAllowedFolders)) {
780
                    array_push($_SESSION['personal_folders'], $persoFld['id']);
781
                    // get all descendants
782
                    $ids = $tree->getDescendants($persoFld['id'], true, false);
783
                    foreach ($ids as $ident) {
784
                        array_push($listAllowedFolders, $ident->id);
785
                        array_push($_SESSION['personal_visible_groups'], $ident->id);
786
                        array_push($_SESSION['personal_folders'], $ident->id);
787
                    }
788
                }
789
            }
790
            // get list of readonly folders when pf is disabled.
791
            $_SESSION['personal_folders'] = array_unique($_SESSION['personal_folders']);
792
            // rule - if one folder is set as W or N in one of the Role, then User has access as W
793
            foreach ($listAllowedFolders as $folderId) {
794
                if (in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders']))) === false) {
795
                    DB::query(
796
                        "SELECT *
797
                        FROM ".prefix_table("roles_values")."
798
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
799
                        $folderId,
800
                        $fonctionsAssociees,
801
                        array("W", "ND", "NE", "NDNE")
802
                    );
803
                    if (DB::count() === 0 && in_array($folderId, $groupesVisiblesUser) === false) {
804
                        array_push($listReadOnlyFolders, $folderId);
805
                    }
806
                }
807
            }
808
        } else {
809
            // get list of readonly folders when pf is disabled.
810
            // rule - if one folder is set as W in one of the Role, then User has access as W
811
            foreach ($listAllowedFolders as $folderId) {
812
                if (in_array($folderId, $listReadOnlyFolders) === false) {
813
                    DB::query(
814
                        "SELECT *
815
                        FROM ".prefix_table("roles_values")."
816
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
817
                        $folderId,
818
                        $fonctionsAssociees,
819
                        array("W", "ND", "NE", "NDNE")
820
                    );
821
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
822
                        array_push($listReadOnlyFolders, $folderId);
823
                    }
824
                }
825
            }
826
        }
827
828
        // check if change proposals on User's items
829
        if (isset($SETTINGS['enable_suggestion']) === true && $SETTINGS['enable_suggestion'] == 1) {
830
            DB::query(
831
                "SELECT *
832
                FROM ".prefix_table("items_change")." AS c
833
                LEFT JOIN ".prefix_table("log_items")." AS i ON (c.item_id = i.id_item)
834
                WHERE i.action = %s AND i.id_user = %i",
835
                "at_creation",
836
                $_SESSION['user_id']
837
            );
838
            $_SESSION['nb_item_change_proposals'] = DB::count();
839
        } else {
840
            $_SESSION['nb_item_change_proposals'] = 0;
841
        }
842
843
        $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
844
        $_SESSION['groupes_visibles'] = $listAllowedFolders;
845
        $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
846
        $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
847
        $_SESSION['read_only_folders'] = $listReadOnlyFolders;
848
        $_SESSION['no_access_folders'] = $groupesInterdits;
849
850
        $_SESSION['list_folders_limited'] = $listFoldersLimited;
851
        $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
852
        $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
853
        // Folders and Roles numbers
854
        DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")."");
855
        $_SESSION['nb_folders'] = DB::count();
856
        DB::queryfirstrow("SELECT id FROM ".prefix_table("roles_title"));
857
        $_SESSION['nb_roles'] = DB::count();
858
    }
859
860
    // update user's timestamp
861
    DB::update(
862
        prefix_table('users'),
863
        array(
864
            'timestamp' => time()
865
        ),
866
        "id=%i",
867
        $_SESSION['user_id']
868
    );
869
}
870
871
/**
872
 * updateCacheTable()
873
 *
874
 * Update the CACHE table
875
 * @param string $action
876
 */
877
function updateCacheTable($action, $ident = "")
878
{
879
    global $server, $user, $pass, $database, $port, $encoding;
880
    global $SETTINGS;
881
882
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
883
884
    //Connect to DB
885
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
886
    $pass = defuse_return_decrypted($pass);
887
    DB::$host = $server;
888
    DB::$user = $user;
889
    DB::$password = $pass;
890
    DB::$dbName = $database;
891
    DB::$port = $port;
892
    DB::$encoding = $encoding;
893
    DB::$error_handler = true;
894
    $link = mysqli_connect($server, $user, $pass, $database, $port);
895
    $link->set_charset($encoding);
896
897
    //Load Tree
898
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
899
    $tree->register();
900
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
901
902
    // Rebuild full cache table
903
    if ($action === "reload") {
904
        // truncate table
905
        DB::query("TRUNCATE TABLE ".prefix_table("cache"));
906
907
        // reload date
908
        $rows = DB::query(
909
            "SELECT *
910
            FROM ".prefix_table('items')." as i
911
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
912
            AND l.action = %s
913
            AND i.inactif = %i",
914
            'at_creation',
915
            0
916
        );
917
        foreach ($rows as $record) {
918
            // Get all TAGS
919
            $tags = "";
920
            $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $record['id']);
921 View Code Duplication
            foreach ($itemTags as $itemTag) {
922
                if (!empty($itemTag['tag'])) {
923
                    $tags .= $itemTag['tag']." ";
924
                }
925
            }
926
            // Get renewal period
927
            $resNT = DB::queryfirstrow("SELECT renewal_period FROM ".prefix_table('nested_tree')." WHERE id=%i", $record['id_tree']);
928
929
            // form id_tree to full foldername
930
            $folder = "";
931
            $arbo = $tree->getPath($record['id_tree'], true);
932 View Code Duplication
            foreach ($arbo as $elem) {
933
                if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
934
                    $elem->title = $_SESSION['login'];
935
                }
936
                if (empty($folder)) {
937
                    $folder = stripslashes($elem->title);
938
                } else {
939
                    $folder .= " » ".stripslashes($elem->title);
940
                }
941
            }
942
            // store data
943
            DB::insert(
944
                prefix_table('cache'),
945
                array(
946
                    'id' => $record['id'],
947
                    'label' => $record['label'],
948
                    'description' => isset($record['description']) ? $record['description'] : "",
949
                    'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : "0",
950
                    'tags' => $tags,
951
                    'id_tree' => $record['id_tree'],
952
                    'perso' => $record['perso'],
953
                    'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : "0",
954
                    'login' => isset($record['login']) ? $record['login'] : "",
955
                    'folder' => $folder,
956
                    'author' => $record['id_user'],
957
                    'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : "0",
958
                    'timestamp' => $record['date']
959
                    )
960
            );
961
        }
962
        // UPDATE an item
963
    } elseif ($action === "update_value") {
964
        // get new value from db
965
        $data = DB::queryfirstrow(
966
            "SELECT label, description, id_tree, perso, restricted_to, login, url
967
            FROM ".prefix_table('items')."
968
            WHERE id=%i",
969
            $ident
970
        );
971
        // Get all TAGS
972
        $tags = "";
973
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $ident);
974 View Code Duplication
        foreach ($itemTags as $itemTag) {
975
            if (!empty($itemTag['tag'])) {
976
                $tags .= $itemTag['tag']." ";
977
            }
978
        }
979
        // form id_tree to full foldername
980
        $folder = "";
981
        $arbo = $tree->getPath($data['id_tree'], true);
982 View Code Duplication
        foreach ($arbo as $elem) {
983
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
984
                $elem->title = $_SESSION['login'];
985
            }
986
            if (empty($folder)) {
987
                $folder = stripslashes($elem->title);
988
            } else {
989
                $folder .= " » ".stripslashes($elem->title);
990
            }
991
        }
992
        // finaly update
993
        DB::update(
994
            prefix_table('cache'),
995
            array(
996
                'label' => $data['label'],
997
                'description' => $data['description'],
998
                'tags' => $tags,
999
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1000
                'id_tree' => $data['id_tree'],
1001
                'perso' => $data['perso'],
1002
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1003
                'login' => isset($data['login']) ? $data['login'] : "",
1004
                'folder' => $folder,
1005
                'author' => $_SESSION['user_id'],
1006
                ),
1007
            "id = %i",
1008
            $ident
1009
        );
1010
        // ADD an item
1011
    } elseif ($action === "add_value") {
1012
        // get new value from db
1013
        $data = DB::queryFirstRow(
1014
            "SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
1015
            FROM ".prefix_table('items')." as i
1016
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
1017
            WHERE i.id = %i
1018
            AND l.action = %s",
1019
            $ident,
1020
            'at_creation'
1021
        );
1022
        // Get all TAGS
1023
        $tags = "";
1024
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id = %i", $ident);
1025 View Code Duplication
        foreach ($itemTags as $itemTag) {
1026
            if (!empty($itemTag['tag'])) {
1027
                $tags .= $itemTag['tag']." ";
1028
            }
1029
        }
1030
        // form id_tree to full foldername
1031
        $folder = "";
1032
        $arbo = $tree->getPath($data['id_tree'], true);
1033 View Code Duplication
        foreach ($arbo as $elem) {
1034
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1035
                $elem->title = $_SESSION['login'];
1036
            }
1037
            if (empty($folder)) {
1038
                $folder = stripslashes($elem->title);
1039
            } else {
1040
                $folder .= " » ".stripslashes($elem->title);
1041
            }
1042
        }
1043
        // finaly update
1044
        DB::insert(
1045
            prefix_table('cache'),
1046
            array(
1047
                'id' => $data['id'],
1048
                'label' => $data['label'],
1049
                'description' => $data['description'],
1050
                'tags' => (isset($tags) && !empty($tags)) ? $tags : "None",
1051
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1052
                'id_tree' => $data['id_tree'],
1053
                'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== "None") ? $data['perso'] : "0",
1054
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "None",
1055
                'login' => isset($data['login']) ? $data['login'] : "",
1056
                'folder' => $folder,
1057
                'author' => $_SESSION['user_id'],
1058
                'timestamp' => $data['date']
1059
            )
1060
        );
1061
1062
        // DELETE an item
1063
    } elseif ($action === "delete_value") {
1064
        DB::delete(prefix_table('cache'), "id = %i", $ident);
1065
    }
1066
}
1067
1068
/*
1069
*
1070
*/
1071
function getStatisticsData()
1072
{
1073
    global $SETTINGS;
1074
1075
    DB::query(
1076
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1077
        0
1078
    );
1079
    $counter_folders = DB::count();
1080
1081
    DB::query(
1082
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1083
        1
1084
    );
1085
    $counter_folders_perso = DB::count();
1086
1087
    DB::query(
1088
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1089
        0
1090
    );
1091
    $counter_items = DB::count();
1092
1093
    DB::query(
1094
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1095
        1
1096
    );
1097
    $counter_items_perso = DB::count();
1098
1099
    DB::query(
1100
        "SELECT id FROM ".prefix_table("users").""
1101
    );
1102
    $counter_users = DB::count();
1103
1104
    DB::query(
1105
        "SELECT id FROM ".prefix_table("users")." WHERE admin = %i",
1106
        1
1107
    );
1108
    $admins = DB::count();
1109
1110
    DB::query(
1111
        "SELECT id FROM ".prefix_table("users")." WHERE gestionnaire = %i",
1112
        1
1113
    );
1114
    $managers = DB::count();
1115
1116
    DB::query(
1117
        "SELECT id FROM ".prefix_table("users")." WHERE read_only = %i",
1118
        1
1119
    );
1120
    $readOnly = DB::count();
1121
1122
    // list the languages
1123
    $usedLang = [];
1124
    $tp_languages = DB::query(
1125
        "SELECT name FROM ".prefix_table("languages")
1126
    );
1127
    foreach ($tp_languages as $tp_language) {
1128
        DB::query(
1129
            "SELECT * FROM ".prefix_table("users")." WHERE user_language = %s",
1130
            $tp_language['name']
1131
        );
1132
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1133
    }
1134
1135
    // get list of ips
1136
    $usedIp = [];
1137
    $tp_ips = DB::query(
1138
        "SELECT user_ip FROM ".prefix_table("users")
1139
    );
1140
    foreach ($tp_ips as $ip) {
1141
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1142
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1143
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== "none") {
1144
            $usedIp[$ip['user_ip']] = 1;
1145
        }
1146
    }
1147
1148
    return array(
1149
        "error" => "",
1150
        "stat_phpversion" => phpversion(),
1151
        "stat_folders" => $counter_folders,
1152
        "stat_folders_shared" => intval($counter_folders) - intval($counter_folders_perso),
1153
        "stat_items" => $counter_items,
1154
        "stat_items_shared" => intval($counter_items) - intval($counter_items_perso),
1155
        "stat_users" => $counter_users,
1156
        "stat_admins" => $admins,
1157
        "stat_managers" => $managers,
1158
        "stat_ro" => $readOnly,
1159
        "stat_kb" => $SETTINGS['enable_kb'],
1160
        "stat_pf" => $SETTINGS['enable_pf_feature'],
1161
        "stat_fav" => $SETTINGS['enable_favourites'],
1162
        "stat_teampassversion" => $SETTINGS['cpassman_version'],
1163
        "stat_ldap" => $SETTINGS['ldap_mode'],
1164
        "stat_agses" => $SETTINGS['agses_authentication_enabled'],
1165
        "stat_duo" => $SETTINGS['duo'],
1166
        "stat_suggestion" => $SETTINGS['enable_suggestion'],
1167
        "stat_api" => $SETTINGS['api'],
1168
        "stat_customfields" => $SETTINGS['item_extra_fields'],
1169
        "stat_syslog" => $SETTINGS['syslog_enable'],
1170
        "stat_2fa" => $SETTINGS['google_authentication'],
1171
        "stat_stricthttps" => $SETTINGS['enable_sts'],
1172
        "stat_mysqlversion" => DB::serverVersion(),
1173
        "stat_languages" => $usedLang,
1174
        "stat_country" => $usedIp
1175
    );
1176
}
1177
1178
/**
1179
 * sendEmail()
1180
 *
1181
 * @return
1182
 */
1183
function sendEmail($subject, $textMail, $email, $textMailAlt = "")
1184
{
1185
    global $LANG;
1186
    global $SETTINGS;
1187
1188
    // CAse where email not defined
1189
    if ($email === "none") {
1190
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1191
    }
1192
1193
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
1194
    //load library
1195
    $user_language = isset($_SESSION['user_language']) ? $_SESSION['user_language'] : "english";
1196
    require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1197
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Email/Phpmailer/PHPMailerAutoload.php';
1198
1199
    // load PHPMailer
1200
    $mail = new PHPMailer();
1201
1202
    // send to user
1203
    $mail->setLanguage("en", "../includes/libraries/Email/Phpmailer/language/");
1204
    $mail->SMTPDebug = 0; //value 1 can be used to debug
1205
    $mail->Port = $SETTINGS['email_port']; //COULD BE USED
1206
    $mail->CharSet = "utf-8";
1207
    if ($SETTINGS['email_security'] === "tls" || $SETTINGS['email_security'] === "ssl") {
1208
        $mail->SMTPSecure = $SETTINGS['email_security'];
1209
    }
1210
    $mail->isSmtp(); // send via SMTP
1211
    $mail->Host = $SETTINGS['email_smtp_server']; // SMTP servers
1212
    $mail->SMTPAuth = $SETTINGS['email_smtp_auth'] == '1' ? true : false; // turn on SMTP authentication
1213
    $mail->Username = $SETTINGS['email_auth_username']; // SMTP username
1214
    $mail->Password = $SETTINGS['email_auth_pwd']; // SMTP password
1215
    $mail->From = $SETTINGS['email_from'];
1216
    $mail->FromName = $SETTINGS['email_from_name'];
1217
    $mail->addAddress($email); //Destinataire
1218
    $mail->WordWrap = 80; // set word wrap
1219
    $mail->isHtml(true); // send as HTML
1220
    $mail->Subject = $subject;
1221
    $mail->Body = $textMail;
1222
    $mail->AltBody = $textMailAlt;
1223
    // send email
1224
    if (!$mail->send()) {
1225
        return '"error":"error_mail_not_send" , "message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1226
    } else {
1227
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1228
    }
1229
}
1230
1231
/**
1232
 * generateKey()
1233
 *
1234
 * @return
1235
 */
1236
function generateKey()
1237
{
1238
    return substr(md5(rand().rand()), 0, 15);
1239
}
1240
1241
/**
1242
 * dateToStamp()
1243
 *
1244
 * @return
1245
 */
1246
function dateToStamp($date)
1247
{
1248
    global $SETTINGS;
1249
1250
    $date = date_parse_from_format($SETTINGS['date_format'], $date);
1251
    if ($date['warning_count'] == 0 && $date['error_count'] == 0) {
1252
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1253
    } else {
1254
        return false;
1255
    }
1256
}
1257
1258
function isDate($date)
1259
{
1260
    return (strtotime($date) !== false);
1261
}
1262
1263
/**
1264
 * isUTF8()
1265
 *
1266
 * @return integer is the string in UTF8 format.
1267
 */
1268
1269
function isUTF8($string)
1270
{
1271
    if (is_array($string) === true) {
1272
        $string = $string['string'];
1273
    }
1274
    return preg_match(
1275
        '%^(?:
1276
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1277
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1278
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1279
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1280
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1281
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1282
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1283
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1284
        )*$%xs',
1285
        $string
1286
    );
1287
}
1288
1289
/*
1290
* FUNCTION
1291
* permits to prepare data to be exchanged
1292
*/
1293
/**
1294
 * @param string $type
1295
 */
1296
function prepareExchangedData($data, $type)
1297
{
1298
    global $SETTINGS;
1299
1300
    //load ClassLoader
1301
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1302
    //Load AES
1303
    $aes = new SplClassLoader('Encryption\Crypt', $SETTINGS['cpassman_dir'].'/includes/libraries');
1304
    $aes->register();
1305
1306
    if ($type == "encode") {
1307
        if (isset($SETTINGS['encryptClientServer'])
1308
            && $SETTINGS['encryptClientServer'] === "0"
1309
        ) {
1310
            return json_encode(
1311
                $data,
1312
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1313
            );
1314 View Code Duplication
        } else {
1315
            return Encryption\Crypt\aesctr::encrypt(
1316
                json_encode(
1317
                    $data,
1318
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1319
                ),
1320
                $_SESSION['key'],
1321
                256
1322
            );
1323
        }
1324
    } elseif ($type == "decode") {
1325
        if (isset($SETTINGS['encryptClientServer'])
1326
            && $SETTINGS['encryptClientServer'] === "0"
1327
        ) {
1328
            return json_decode(
1329
                $data,
1330
                true
1331
            );
1332
        } else {
1333
            return json_decode(
1334
                Encryption\Crypt\aesctr::decrypt(
1335
                    $data,
1336
                    $_SESSION['key'],
1337
                    256
1338
                ),
1339
                true
1340
            );
1341
        }
1342
    }
1343
}
1344
1345
function make_thumb($src, $dest, $desired_width)
1346
{
1347
    /* read the source image */
1348
    $source_image = imagecreatefrompng($src);
1349
    $width = imagesx($source_image);
1350
    $height = imagesy($source_image);
1351
1352
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1353
    $desired_height = floor($height * ($desired_width / $width));
1354
1355
    /* create a new, "virtual" image */
1356
    $virtual_image = imagecreatetruecolor($desired_width, $desired_height);
1357
1358
    /* copy source image at a resized size */
1359
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
1360
1361
    /* create the physical thumbnail image to its destination */
1362
    imagejpeg($virtual_image, $dest);
1363
}
1364
1365
/*
1366
** check table prefix in SQL query
1367
*/
1368
/**
1369
 * @param string $table
1370
 */
1371
function prefix_table($table)
1372
{
1373
    global $pre;
1374
    $safeTable = htmlspecialchars($pre.$table);
1375
    if (!empty($safeTable)) {
1376
        // sanitize string
1377
        return $safeTable;
1378
    } else {
1379
        // stop error no table
1380
        return "table_not_exists";
1381
    }
1382
}
1383
1384
/*
1385
 * Creates a KEY using PasswordLib
1386
 */
1387
function GenerateCryptKey($size = "", $secure = false, $numerals = false, $capitalize = false, $ambiguous = false, $symbols = false)
1388
{
1389
    global $SETTINGS;
1390
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1391
1392
    // load library
1393
    $pwgen = new SplClassLoader('Encryption\PwGen', $SETTINGS['cpassman_dir'].'/includes/libraries');
1394
    $pwgen->register();
1395
    $pwgen = new Encryption\PwGen\pwgen();
1396
1397
    // init
1398
    if (!empty($size)) {
1399
        $pwgen->setLength($size);
1400
    }
1401
    if (!empty($secure)) {
1402
        $pwgen->setSecure($secure);
1403
    }
1404
    if (!empty($numerals)) {
1405
        $pwgen->setNumerals($numerals);
1406
    }
1407
    if (!empty($capitalize)) {
1408
        $pwgen->setCapitalize($capitalize);
1409
    }
1410
    if (!empty($ambiguous)) {
1411
        $pwgen->setAmbiguous($ambiguous);
1412
    }
1413
    if (!empty($symbols)) {
1414
        $pwgen->setSymbols($symbols);
1415
    }
1416
1417
    // generate and send back
1418
    return $pwgen->generate();
1419
}
1420
1421
/*
1422
* Send sysLOG message
1423
* @param string $message
1424
* @param string $host
1425
*/
1426
function send_syslog($message, $host, $port, $component = "teampass")
1427
{
1428
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1429
    $syslog_message = "<123>".date('M d H:i:s ').$component.": ".$message;
1430
    socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1431
    socket_close($sock);
1432
}
1433
1434
1435
1436
/**
1437
 * logEvents()
1438
 *
1439
 * permits to log events into DB
1440
 * @param string $type
1441
 * @param string $label
1442
 * @param string $field_1
1443
 */
1444
function logEvents($type, $label, $who, $login = "", $field_1 = null)
1445
{
1446
    global $server, $user, $pass, $database, $port, $encoding;
1447
    global $SETTINGS;
1448
1449
    if (empty($who)) {
1450
        $who = get_client_ip_server();
1451
    }
1452
1453
    // include librairies & connect to DB
1454
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1455
    $pass = defuse_return_decrypted($pass);
1456
    DB::$host = $server;
1457
    DB::$user = $user;
1458
    DB::$password = $pass;
1459
    DB::$dbName = $database;
1460
    DB::$port = $port;
1461
    DB::$encoding = $encoding;
1462
    DB::$error_handler = true;
1463
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1464
    $link->set_charset($encoding);
1465
1466
    DB::insert(
1467
        prefix_table("log_system"),
1468
        array(
1469
            'type' => $type,
1470
            'date' => time(),
1471
            'label' => $label,
1472
            'qui' => $who,
1473
            'field_1' => $field_1 === null ? "" : $field_1
1474
        )
1475
    );
1476
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1477
        if ($type == "user_mngt") {
1478
            send_syslog(
1479
                "The User ".$login." performed the action of ".$label." to the user ".$field_1." - ".$type,
1480
                $SETTINGS['syslog_host'],
1481
                $SETTINGS['syslog_port'],
1482
                "teampass"
1483
            );
1484
        } else {
1485
            send_syslog(
1486
                "The User ".$login." performed the action of ".$label." - ".$type,
1487
                $SETTINGS['syslog_host'],
1488
                $SETTINGS['syslog_port'],
1489
                "teampass"
1490
            );
1491
        }
1492
    }
1493
}
1494
1495
/**
1496
 * @param string $item
1497
 * @param string $action
1498
 */
1499
function logItems($ident, $item, $id_user, $action, $login = "", $raison = null, $raison_iv = null, $encryption_type = "")
1500
{
1501
    global $server, $user, $pass, $database, $port, $encoding;
1502
    global $SETTINGS;
1503
1504
    // include librairies & connect to DB
1505
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1506
    $pass = defuse_return_decrypted($pass);
1507
    DB::$host = $server;
1508
    DB::$user = $user;
1509
    DB::$password = $pass;
1510
    DB::$dbName = $database;
1511
    DB::$port = $port;
1512
    DB::$encoding = $encoding;
1513
    DB::$error_handler = true;
1514
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1515
    $link->set_charset($encoding);
1516
    DB::insert(
1517
        prefix_table("log_items"),
1518
        array(
1519
            'id_item' => $ident,
1520
            'date' => time(),
1521
            'id_user' => $id_user,
1522
            'action' => $action,
1523
            'raison' => $raison,
1524
            'raison_iv' => $raison_iv,
1525
            'encryption_type' => $encryption_type
1526
        )
1527
    );
1528
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1529
        send_syslog(
1530
            "The Item ".$item." was ".$action." by ".$login." ".$raison,
1531
            $SETTINGS['syslog_host'],
1532
            $SETTINGS['syslog_port'],
1533
            "teampass"
1534
        );
1535
    }
1536
}
1537
1538
/*
1539
* Function to get the client ip address
1540
 */
1541
function get_client_ip_server()
1542
{
1543
    if (getenv('HTTP_CLIENT_IP')) {
1544
            $ipaddress = getenv('HTTP_CLIENT_IP');
1545
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1546
            $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1547
    } elseif (getenv('HTTP_X_FORWARDED')) {
1548
            $ipaddress = getenv('HTTP_X_FORWARDED');
1549
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1550
            $ipaddress = getenv('HTTP_FORWARDED_FOR');
1551
    } elseif (getenv('HTTP_FORWARDED')) {
1552
            $ipaddress = getenv('HTTP_FORWARDED');
1553
    } elseif (getenv('REMOTE_ADDR')) {
1554
            $ipaddress = getenv('REMOTE_ADDR');
1555
    } else {
1556
            $ipaddress = 'UNKNOWN';
1557
    }
1558
1559
    return $ipaddress;
1560
}
1561
1562
/**
1563
 * Escape all HTML, JavaScript, and CSS
1564
 *
1565
 * @param string $input The input string
1566
 * @param string $encoding Which character encoding are we using?
1567
 * @return string
1568
 */
1569
function noHTML($input, $encoding = 'UTF-8')
1570
{
1571
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1572
}
1573
1574
/**
1575
 * handleConfigFile()
1576
 *
1577
 * permits to handle the Teampass config file
1578
 * $action accepts "rebuild" and "update"
1579
 */
1580
function handleConfigFile($action, $field = null, $value = null)
1581
{
1582
    global $server, $user, $pass, $database, $port, $encoding;
1583
    global $SETTINGS;
1584
1585
    $tp_config_file = "../includes/config/tp.config.php";
1586
1587
    // Load AntiXSS
1588
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
1589
    $antiXss = new protect\AntiXSS\AntiXSS();
1590
1591
    // include librairies & connect to DB
1592
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1593
    $pass = defuse_return_decrypted($pass);
1594
    DB::$host = $server;
1595
    DB::$user = $user;
1596
    DB::$password = $pass;
1597
    DB::$dbName = $database;
1598
    DB::$port = $port;
1599
    DB::$encoding = $encoding;
1600
    DB::$error_handler = true;
1601
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1602
    $link->set_charset($encoding);
1603
1604
    if (!file_exists($tp_config_file) || $action == "rebuild") {
1605
        // perform a copy
1606
        if (file_exists($tp_config_file)) {
1607
            if (!copy($tp_config_file, $tp_config_file.'.'.date("Y_m_d_His", time()))) {
1608
                return "ERROR: Could not copy file '".$tp_config_file."'";
1609
            }
1610
        }
1611
1612
        // regenerate
1613
        $data = array();
1614
        $data[0] = "<?php\n";
1615
        $data[1] = "global \$SETTINGS;\n";
1616
        $data[2] = "\$SETTINGS = array (\n";
1617
        $rows = DB::query(
1618
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s",
1619
            "admin"
1620
        );
1621
        foreach ($rows as $record) {
1622
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
1623
        }
1624
        array_push($data, ");");
1625
        $data = array_unique($data);
1626
    } elseif ($action == "update" && !empty($field)) {
1627
        $data = file($tp_config_file);
1628
        $inc = 0;
1629
        $bFound = false;
1630
        foreach ($data as $line) {
1631
            if (stristr($line, ");")) {
1632
                break;
1633
            }
1634
1635
            //
1636
            if (stristr($line, "'".$field."' => '")) {
1637
                $data[$inc] = "    '".$field."' => '".$antiXss->xss_clean($value)."',\n";
1638
                $bFound = true;
1639
                break;
1640
            }
1641
            $inc++;
1642
        }
1643
        if ($bFound === false) {
1644
            $data[($inc - 1)] = "    '".$field."' => '".$antiXss->xss_clean($value)."',\n";
1645
        }
1646
    }
1647
1648
    // update file
1649
    file_put_contents($tp_config_file, implode('', isset($data) ? $data : array()));
1650
1651
    return true;
1652
}
1653
1654
/*
1655
** Permits to replace &#92; to permit correct display
1656
*/
1657
/**
1658
 * @param string $input
1659
 */
1660
function handleBackslash($input)
1661
{
1662
    return str_replace("&amp;#92;", "&#92;", $input);
1663
}
1664
1665
/*
1666
** Permits to loas settings
1667
*/
1668
function loadSettings()
1669
{
1670
    global $SETTINGS;
1671
1672
    /* LOAD CPASSMAN SETTINGS */
1673
    if (!isset($SETTINGS['loaded']) || $SETTINGS['loaded'] != 1) {
1674
        $SETTINGS['duplicate_folder'] = 0; //by default, this is set to 0;
1675
        $SETTINGS['duplicate_item'] = 0; //by default, this is set to 0;
1676
        $SETTINGS['number_of_used_pw'] = 5; //by default, this value is set to 5;
1677
        $settings = array();
1678
1679
        $rows = DB::query(
1680
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s_type OR type=%s_type2",
1681
            array(
1682
                'type' => "admin",
1683
                'type2' => "settings"
1684
            )
1685
        );
1686
        foreach ($rows as $record) {
1687
            if ($record['type'] == 'admin') {
1688
                $SETTINGS[$record['intitule']] = $record['valeur'];
1689
            } else {
1690
                $settings[$record['intitule']] = $record['valeur'];
1691
            }
1692
        }
1693
        $SETTINGS['loaded'] = 1;
1694
        $SETTINGS['default_session_expiration_time'] = 5;
1695
    }
1696
}
1697
1698
/*
1699
** check if folder has custom fields.
1700
** Ensure that target one also has same custom fields
1701
*/
1702
function checkCFconsistency($source_id, $target_id)
1703
{
1704
    $source_cf = array();
1705
    $rows = DB::QUERY(
1706
        "SELECT id_category
1707
        FROM ".prefix_table("categories_folders")."
1708
        WHERE id_folder = %i",
1709
        $source_id
1710
    );
1711
    foreach ($rows as $record) {
1712
        array_push($source_cf, $record['id_category']);
1713
    }
1714
1715
    $target_cf = array();
1716
    $rows = DB::QUERY(
1717
        "SELECT id_category
1718
        FROM ".prefix_table("categories_folders")."
1719
        WHERE id_folder = %i",
1720
        $target_id
1721
    );
1722
    foreach ($rows as $record) {
1723
        array_push($target_cf, $record['id_category']);
1724
    }
1725
1726
    $cf_diff = array_diff($source_cf, $target_cf);
1727
    if (count($cf_diff) > 0) {
1728
        return false;
1729
    }
1730
1731
    return true;
1732
}
1733
1734
/*
1735
*
1736
*/
1737
function encrypt_or_decrypt_file($filename_to_rework, $filename_status)
1738
{
1739
    global $server, $user, $pass, $database, $port, $encoding;
1740
    global $SETTINGS;
1741
1742
    // Include librairies & connect to DB
1743
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1744
    $pass = defuse_return_decrypted($pass);
1745
    DB::$host = $server;
1746
    DB::$user = $user;
1747
    DB::$password = $pass;
1748
    DB::$dbName = $database;
1749
    DB::$port = $port;
1750
    DB::$encoding = $encoding;
1751
    DB::$error_handler = true;
1752
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1753
    $link->set_charset($encoding);
1754
1755
    // Get file info in DB
1756
    $fileInfo = DB::queryfirstrow(
1757
        "SELECT id FROM ".prefix_table("files")." WHERE file = %s",
1758
        filter_var($filename_to_rework, FILTER_SANITIZE_STRING)
1759
    );
1760
    if (empty($fileInfo['id']) === false) {
1761
        // Load PhpEncryption library
1762
        $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
1763
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
1764
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
1765
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
1766
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
1767
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
1768
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
1769
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
1770
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
1771
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
1772
1773
        // Get KEY
1774
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
1775
1776
        if (isset($SETTINGS['enable_attachment_encryption'])
1777
            && $SETTINGS['enable_attachment_encryption'] === "1" &&
1778
            isset($filename_status)
1779
            && ($filename_status === "clear"
1780
                || $filename_status === "0")
1781
        ) {
1782
            // File needs to be encrypted
1783 View Code Duplication
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1784
                // Make a copy of file
1785
                if (!copy(
1786
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1787
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1788
                )) {
1789
                    exit;
1790
                } else {
1791
                    // Do a bck
1792
                    copy(
1793
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1794
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1795
                    );
1796
                }
1797
1798
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1799
1800
                // Now encrypt the file with saltkey
1801
                $err = '';
1802
                try {
1803
                    \Defuse\Crypto\File::encryptFile(
1804
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1805
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1806
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1807
                    );
1808
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1809
                    $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.";
1810
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1811
                    $err = $ex;
1812
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1813
                    $err = $ex;
1814
                }
1815
                if (empty($err) === false) {
1816
                    echo $err;
1817
                }
1818
1819
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1820
1821
                // update table
1822
                DB::update(
1823
                    prefix_table('files'),
1824
                    array(
1825
                        'status' => 'encrypted'
1826
                        ),
1827
                    "id = %i",
1828
                    $fileInfo['id']
1829
                );
1830
            }
1831
        } elseif (isset($SETTINGS['enable_attachment_encryption'])
1832
            && $SETTINGS['enable_attachment_encryption'] === "0"
1833
            && isset($filename_status)
1834
            && $filename_status === "encrypted"
1835
        ) {
1836
            // file needs to be decrypted
1837 View Code Duplication
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1838
                // make a copy of file
1839
                if (!copy(
1840
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1841
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1842
                )) {
1843
                    exit;
1844
                } else {
1845
                    // do a bck
1846
                    copy(
1847
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1848
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1849
                    );
1850
                }
1851
1852
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1853
1854
                // Now encrypt the file with saltkey
1855
                $err = '';
1856
                try {
1857
                    \Defuse\Crypto\File::decryptFile(
1858
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1859
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1860
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1861
                    );
1862
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1863
                    $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.";
1864
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1865
                    $err = $ex;
1866
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1867
                    $err = $ex;
1868
                }
1869
                if (empty($err) === false) {
1870
                    echo $err;
1871
                }
1872
1873
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1874
1875
                // update table
1876
                DB::update(
1877
                    prefix_table('files'),
1878
                    array(
1879
                        'status' => 'clear'
1880
                        ),
1881
                    "id = %i",
1882
                    $fileInfo['id']
1883
                );
1884
            }
1885
        }
1886
    }
1887
1888
    // Exit
1889
    return false;
1890
}
1891
1892
/**
1893
 * Will encrypte/decrypt a fil eusing Defuse
1894
 * @param  string $type        can be either encrypt or decrypt
1895
 * @param  string $source_file path to source file
1896
 * @param  string $target_file path to target file
1897
 * @return string              'true' is success or error message
1898
 */
1899
function prepareFileWithDefuse($type, $source_file, $target_file, $password = '')
1900
{
1901
    global $SETTINGS;
1902
1903
    // Load AntiXSS
1904
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
1905
    $antiXss = new protect\AntiXSS\AntiXSS();
1906
1907
    // Protect against bad inputs
1908
    if (is_array($source_file) ||is_array($target_file)) {
1909
        return 'error_cannot_be_array';
1910
    }
1911
1912
    // Sanitize
1913
    $source_file = $antiXss->xss_clean($source_file);
1914
    $target_file = $antiXss->xss_clean($target_file);
1915
1916
    // load PhpEncryption library
1917
    $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
1918
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
1919
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
1920
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
1921
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
1922
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
1923
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
1924
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
1925
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
1926
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
1927
1928
    if (empty($password) === true) {
1929
    /*
1930
    File encryption/decryption is done with the SALTKEY
1931
     */
1932
1933
        // get KEY
1934
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
1935
1936
        // Now perform action on the file
1937
        $err = '';
1938 View Code Duplication
        if ($type === 'decrypt') {
1939
            try {
1940
                \Defuse\Crypto\File::decryptFile(
1941
                    $source_file,
0 ignored issues
show
Bug introduced by
It seems like $source_file defined by $antiXss->xss_clean($source_file) on line 1913 can also be of type array; however, Defuse\Crypto\File::decryptFile() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1942
                    $target_file,
0 ignored issues
show
Bug introduced by
It seems like $target_file defined by $antiXss->xss_clean($target_file) on line 1914 can also be of type array; however, Defuse\Crypto\File::decryptFile() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1943
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1944
                );
1945
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1946
                $err = "decryption_not_possible";
1947
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1948
                $err = $ex;
1949
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1950
                $err = $ex;
1951
            }
1952
        } elseif ($type === 'encrypt') {
1953
            try {
1954
                \Defuse\Crypto\File::encryptFile(
1955
                    $source_file,
0 ignored issues
show
Bug introduced by
It seems like $source_file defined by $antiXss->xss_clean($source_file) on line 1913 can also be of type array; however, Defuse\Crypto\File::encryptFile() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1956
                    $target_file,
0 ignored issues
show
Bug introduced by
It seems like $target_file defined by $antiXss->xss_clean($target_file) on line 1914 can also be of type array; however, Defuse\Crypto\File::encryptFile() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1957
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1958
                );
1959
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1960
                $err = "encryption_not_possible";
1961
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1962
                $err = $ex;
1963
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1964
                $err = $ex;
1965
            }
1966
        }
1967
    } else {
1968
    /*
1969
    File encryption/decryption is done with special password and not the SALTKEY
1970
     */
1971
1972
        $err = '';
1973 View Code Duplication
        if ($type === 'decrypt') {
1974
            try {
1975
                \Defuse\Crypto\File::decryptFileWithPassword(
1976
                    $source_file,
0 ignored issues
show
Bug introduced by
It seems like $source_file defined by $antiXss->xss_clean($source_file) on line 1913 can also be of type array; however, Defuse\Crypto\File::decryptFileWithPassword() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1977
                    $target_file,
0 ignored issues
show
Bug introduced by
It seems like $target_file defined by $antiXss->xss_clean($target_file) on line 1914 can also be of type array; however, Defuse\Crypto\File::decryptFileWithPassword() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1978
                    $password
1979
                );
1980
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1981
                $err = "wrong_key";
1982
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1983
                $err = $ex;
1984
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1985
                $err = $ex;
1986
            }
1987
        } elseif ($type === 'encrypt') {
1988
            try {
1989
                \Defuse\Crypto\File::encryptFileWithPassword(
1990
                    $source_file,
0 ignored issues
show
Bug introduced by
It seems like $source_file defined by $antiXss->xss_clean($source_file) on line 1913 can also be of type array; however, Defuse\Crypto\File::encryptFileWithPassword() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1991
                    $target_file,
0 ignored issues
show
Bug introduced by
It seems like $target_file defined by $antiXss->xss_clean($target_file) on line 1914 can also be of type array; however, Defuse\Crypto\File::encryptFileWithPassword() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1992
                    $password
1993
                );
1994
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1995
                $err = "wrong_key";
1996
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1997
                $err = $ex;
1998
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1999
                $err = $ex;
2000
            }
2001
        }
2002
    }
2003
2004
    // return error
2005
    if (empty($err) === false) {
2006
        return $err;
2007
    } else {
2008
        return true;
2009
    }
2010
}
2011
2012
/*
2013
* NOT TO BE USED
2014
*/
2015
function debugTeampass($text)
2016
{
2017
    $debugFile = fopen('D:/wamp64/www/TeamPass/debug.txt', 'r+');
2018
    fputs($debugFile, $text);
2019
    fclose($debugFile);
2020
}
2021
2022
2023
/**
2024
 * DELETE the file with expected command depending on server type
2025
 * @param  string $file Path to file
2026
 * @return              Nothing
2027
 */
2028
function fileDelete($file)
2029
{
2030
    global $SETTINGS;
2031
2032
    // Load AntiXSS
2033
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2034
    $antiXss = new protect\AntiXSS\AntiXSS();
2035
2036
    $file = $antiXss->xss_clean($file);
2037
    if (is_file($file)) {
2038
        unlink($file);
2039
    }
2040
}
2041
2042
/*
2043
* Permits to extract the file extension
2044
*/
2045
function getFileExtension($file)
2046
{
2047
    if (strpos($file, '.') === false) {
2048
        return $file;
2049
    }
2050
2051
    return substr($file, strrpos($file, '.') + 1);
2052
}
2053
2054
/**
2055
 * array_map
2056
 * @param  [type] $func [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
2057
 * @param  [type] $arr  [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
2058
 * @return [type]       [description]
0 ignored issues
show
Documentation introduced by
The doc-type [type] could not be parsed: Unknown type name "" at position 0. [(view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
2059
 */
2060
function array_map_r($func, $arr)
2061
{
2062
    $newArr = array();
2063
2064
    foreach ($arr as $key => $value) {
2065
        $newArr[ $key ] = (is_array($value) ? array_map_r($func, $value) : ( is_array($func) ? call_user_func_array($func, $value) : $func( $value )));
2066
    }
2067
2068
    return $newArr;
2069
}
2070
2071
/**
2072
 * Permits to clean and sanitize text to be displayed
2073
 * @param  string $text text to clean
0 ignored issues
show
Bug introduced by
There is no parameter named $text. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
2074
 * @param  string $type what clean to perform
2075
 * @return string       text cleaned up
2076
 */
2077
function cleanText($string, $type = "")
2078
{
2079
    global $SETTINGS;
2080
2081
    // Load AntiXSS
2082
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2083
    $antiXss = new protect\AntiXSS\AntiXSS();
2084
2085
    if ($type === "css") {
2086
        // Escape text and quotes in UTF8 format
2087
        return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2088
    } elseif ($type === "html" || empty($type)) {
2089
        // Html cleaner
2090
        return $antiXss->xss_clean($string);
2091
    }
2092
}
2093
2094
/**
2095
 * Performs chmod operation on subfolders
2096
 * @param  string  $dir             Parent folder
2097
 * @param  integer $dirPermissions  New permission on folders
2098
 * @param  integer $filePermissions New permission on files
2099
 * @return boolean                  Success/Failure
2100
 */
2101
function chmodRecursive($dir, $dirPermissions, $filePermissions)
2102
{
2103
    $pointer_dir = opendir($dir);
2104
    $res = true;
2105
    while ($file = readdir($pointer_dir)) {
2106
        if (($file == ".") || ($file == "..")) {
2107
            continue;
2108
        }
2109
2110
        $fullPath = $dir."/".$file;
2111
2112
        if (is_dir($fullPath)) {
2113
            if ($res = @chmod($fullPath, $dirPermissions)) {
2114
                $res = @chmodRecursive($fullPath, $dirPermissions, $filePermissions);
2115
            }
2116
        } else {
2117
            $res = chmod($fullPath, $filePermissions);
2118
        }
2119
        if (!$res) {
2120
            closedir($pointer_dir);
2121
            return false;
2122
        }
2123
    }
2124
    closedir($pointer_dir);
2125
    if (is_dir($dir) && $res) {
2126
        $res = @chmod($dir, $dirPermissions);
2127
    }
2128
2129
    return $res;
2130
}
2131
2132
/**
2133
 * Check if user can access to this item
2134
 * @param $item_id
2135
 */
2136
function accessToItemIsGranted($item_id)
2137
{
2138
    global $SETTINGS;
2139
2140
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2141
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2142
2143
    // Prepare superGlobal variables
2144
    $session_groupes_visibles = $superGlobal->get("groupes_visibles", "SESSION");
2145
    $session_list_restricted_folders_for_items = $superGlobal->get("list_restricted_folders_for_items", "SESSION");
2146
2147
    // Load item data
2148
    $data = DB::queryFirstRow(
2149
        "SELECT id_tree
2150
        FROM ".prefix_table("items")."
2151
        WHERE id = %i",
2152
        $item_id
2153
    );
2154
2155
    // Check if user can access this folder
2156
    if (in_array($data['id_tree'], $session_groupes_visibles) === false) {
2157
        // Now check if this folder is restricted to user
2158
        if (isset($session_list_restricted_folders_for_items[$data['id_tree']])
2159
            && !in_array($item_id, $session_list_restricted_folders_for_items[$data['id_tree']])
2160
        ) {
2161
            return "ERR_FOLDER_NOT_ALLOWED";
2162
        } else {
2163
            return "ERR_FOLDER_NOT_ALLOWED";
2164
        }
2165
    }
2166
2167
    return true;
2168
}
2169