Completed
Push — development ( 676bb1...171946 )
by Nils
08:33
created

main.functions.php ➔ chmodRecursive()   D

Complexity

Conditions 9
Paths 13

Size

Total Lines 30
Code Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 19
nc 13
nop 3
dl 0
loc 30
rs 4.909
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 = SALT;
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 View Code Duplication
function bCrypt($password, $cost)
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...
Best Practice introduced by
The function bCrypt() has been defined more than once; this definition is ignored, only the first definition in install/install.queries.php (L57-69) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

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

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
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...
2079
{
2080
    $pointer_dir = opendir($dir);
0 ignored issues
show
Security File Exposure introduced by
$dir can contain request data and is used in file inclusion context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_GET
    in includes/libraries/protect/SuperGlobal/SuperGlobal.php on line 45
  2. SuperGlobal::get() returns tainted data, and $session_abspath is assigned
    in install/install.queries.php on line 130
  3. $session_abspath is passed to chmodRecursive()
    in install/install.queries.php on line 1145

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
2081
    $res = true;
2082
    while ($file = readdir($pointer_dir)) {
2083
        if (($file == ".") || ($file == "..")) {
2084
            continue;
2085
        }
2086
2087
        $fullPath = $dir."/".$file;
2088
2089
        if (is_dir($fullPath)) {
2090
            if ($res = @chmod($fullPath, $dirPermissions)) {
0 ignored issues
show
Security File Manipulation introduced by
$fullPath can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_GET
    in includes/libraries/protect/SuperGlobal/SuperGlobal.php on line 45
  2. SuperGlobal::get() returns tainted data, and $session_abspath is assigned
    in install/install.queries.php on line 130
  3. $session_abspath is passed to chmodRecursive()
    in install/install.queries.php on line 1145
  4. $fullPath is assigned
    in sources/main.functions.php on line 2087

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
2091
                $res = @chmodRecursive($fullPath, $dirPermissions, $filePermissions);
2092
            }
2093
        } else {
2094
            $res = chmod($fullPath, $filePermissions);
0 ignored issues
show
Security File Manipulation introduced by
$fullPath can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_GET
    in includes/libraries/protect/SuperGlobal/SuperGlobal.php on line 45
  2. SuperGlobal::get() returns tainted data, and $session_abspath is assigned
    in install/install.queries.php on line 130
  3. $session_abspath is passed to chmodRecursive()
    in install/install.queries.php on line 1145
  4. $fullPath is assigned
    in sources/main.functions.php on line 2087

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
2095
        }
2096
        if (!$res) {
2097
            closedir($pointer_dir);
2098
            return false;
2099
        }
2100
    }
2101
    closedir($pointer_dir);
2102
    if (is_dir($dir) && $res) {
2103
        $res = @chmod($dir, $dirPermissions);
0 ignored issues
show
Security File Manipulation introduced by
$dir can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

1 path for user data to reach this point

  1. Read from $_GET
    in includes/libraries/protect/SuperGlobal/SuperGlobal.php on line 45
  2. SuperGlobal::get() returns tainted data, and $session_abspath is assigned
    in install/install.queries.php on line 130
  3. $session_abspath is passed to chmodRecursive()
    in install/install.queries.php on line 1145

General Strategies to prevent injection

In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:

if ( ! in_array($value, array('this-is-allowed', 'and-this-too'), true)) {
    throw new \InvalidArgumentException('This input is not allowed.');
}

For numeric data, we recommend to explicitly cast the data:

$sanitized = (integer) $tainted;
Loading history...
2104
    }
2105
2106
    return $res;
2107
}
2108