Completed
Push — development ( 525d4d...8af731 )
by Nils
07:12
created

main.functions.php ➔ bCrypt()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 13
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 9
nc 2
nop 2
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
1
<?php
2
/**
3
 *
4
 * @file          main.functions.php
5
 * @author        Nils Laumaillé
6
 * @version       2.1.27
7
 * @copyright     (c) 2009-2017 Nils Laumaillé
8
 * @licensing     GNU AFFERO GPL 3.0
9
 * @link
10
 */
11
12
//define pbkdf2 iteration count
13
define('ITCOUNT', '2072');
14
15
if (!isset($_SESSION['CPM']) || $_SESSION['CPM'] != 1) {
16
    die('Hacking attempt...');
17
}
18
19
// Load config
20 View Code Duplication
if (file_exists('../includes/config/tp.config.php')) {
21
    require_once '../includes/config/tp.config.php';
22
} elseif (file_exists('./includes/config/tp.config.php')) {
23
    require_once './includes/config/tp.config.php';
24
} elseif (file_exists('../../includes/config/tp.config.php')) {
25
    require_once '../../includes/config/tp.config.php';
26
} else {
27
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
28
}
29
30
// load phpCrypt
31
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
32
    require_once '../includes/libraries/phpcrypt/phpCrypt.php';
33
    require_once '../includes/config/settings.php';
34
} else {
35
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/phpcrypt/phpCrypt.php';
36
    require_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
37
}
38
39
// Prepare PHPCrypt class calls
40
use PHP_Crypt\PHP_Crypt as PHP_Crypt;
41
42
// Prepare Encryption class calls
43
use \Defuse\Crypto\Crypto;
44
use \Defuse\Crypto\Exception as Ex;
45
46
//Generate N# of random bits for use as salt
47
/**
48
 * @param integer $n
49
 */
50
function getBits($n)
51
{
52
    $str = '';
53
    $x = $n + 10;
54
    for ($i = 0; $i < $x; $i++) {
55
        $str .= base_convert(mt_rand(1, 36), 10, 36);
56
    }
57
    return substr($str, 0, $n);
58
}
59
60
//generate pbkdf2 compliant hash
61 View Code Duplication
function strHashPbkdf2($p, $s, $c, $kl, $a = 'sha256', $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
    $kb = $st + $kl; // Key blocks to compute
64
    $dk = ''; // Derived key
65
66
    for ($block = 1; $block <= $kb; $block++) { // Create key
67
        $ib = $h = hash_hmac($a, $s.pack('N', $block), $p, true); // Initial hash for this block
68
        for ($i = 1; $i < $c; $i++) { // Perform block iterations
69
            $ib ^= ($h = hash_hmac($a, $h, $p, true)); // XOR each iterate
70
        }
71
        $dk .= $ib; // Append iterated block
72
    }
73
    return substr($dk, $st, $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 View Code Duplication
function encryptOld($text, $personalSalt = "")
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...
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 View Code Duplication
function decryptOld($text, $personalSalt = "")
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...
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
    } else {
149
        return trim(
150
            mcrypt_decrypt(
151
                MCRYPT_RIJNDAEL_256,
152
                SALT,
153
                base64_decode($text),
154
                MCRYPT_MODE_ECB,
155
                mcrypt_create_iv(
156
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
157
                    MCRYPT_RAND
158
                )
159
            )
160
        );
161
    }
162
}
163
164
/**
165
 * encrypt()
166
 *
167
 * crypt a string
168
 * @param string $decrypted
169
 */
170
function encrypt($decrypted, $personalSalt = "")
171
{
172
    global $SETTINGS;
173
174 View Code Duplication
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
175
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
176
    } else {
177
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
178
    }
179
180
    if (!empty($personalSalt)) {
181
            $staticSalt = $personalSalt;
182
    } else {
183
            $staticSalt = SALT;
184
    }
185
186
    //set our salt to a variable
187
    // Get 64 random bits for the salt for pbkdf2
188
    $pbkdf2Salt = getBits(64);
189
    // generate a pbkdf2 key to use for the encryption.
190
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
191
    // Build $iv and $ivBase64.  We use a block size of 256 bits (AES compliant)
192
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
193
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);
194
195
    //base64 trim
196
    if (strlen($ivBase64 = rtrim(base64_encode($iv), '=')) != 43) {
197
        return false;
198
    }
199
    // Encrypt $decrypted
200
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $iv);
201
    // MAC the encrypted text
202
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
203
    // We're done!
204
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
205
}
206
207
/**
208
 * decrypt()
209
 *
210
 * decrypt a crypted string
211
 */
212
function decrypt($encrypted, $personalSalt = "")
213
{
214
    global $SETTINGS;
215
216 View Code Duplication
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
217
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
218
    } else {
219
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
220
    }
221
222
    if (!empty($personalSalt)) {
223
        $staticSalt = $personalSalt;
224
    } else {
225
        $staticSalt = SALT;
226
    }
227
    //base64 decode the entire payload
228
    $encrypted = base64_decode($encrypted);
229
    // get the salt
230
    $pbkdf2Salt = substr($encrypted, -64);
231
    //remove the salt from the string
232
    $encrypted = substr($encrypted, 0, -64);
233
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
234
    // Retrieve $iv which is the first 22 characters plus ==, base64_decoded.
235
    $iv = base64_decode(substr($encrypted, 0, 43).'==');
236
    // Remove $iv from $encrypted.
237
    $encrypted = substr($encrypted, 43);
238
    // Retrieve $mac which is the last 64 characters of $encrypted.
239
    $mac = substr($encrypted, -64);
240
    // Remove the last 64 chars from encrypted (remove MAC)
241
    $encrypted = substr($encrypted, 0, -64);
242
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
243
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
244
        return false;
245
    }
246
    // Decrypt the data.
247
    $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $iv), "\0\4");
248
    // Yay!
249
    return $decrypted;
250
}
251
252
253
/**
254
 * genHash()
255
 *
256
 * Generate a hash for user login
257
 * @param string $password
258
 */
259
function bCrypt($password, $cost)
260
{
261
    $salt = sprintf('$2y$%02d$', $cost);
262
    if (function_exists('openssl_random_pseudo_bytes')) {
263
        $salt .= bin2hex(openssl_random_pseudo_bytes(11));
264
    } else {
265
        $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
266
        for ($i = 0; $i < 22; $i++) {
267
            $salt .= $chars[mt_rand(0, 63)];
268
        }
269
    }
270
    return crypt($password, $salt);
271
}
272
273
function cryption_before_defuse($message, $sk, $iv, $type = null, $scope = "public")
274
{
275
    if (DEFUSE_ENCRYPTION === true) {
276
        if ($scope === "perso") {
277
            return defuse_crypto(
278
                $message,
279
                $sk,
280
                $type
281
            );
282
        } else {
283
            return defuse_crypto(
284
                $message,
285
                file_get_contents(SECUREPATH."/teampass-seckey.txt"),
286
                $type
287
            );
288
        }
289
    } else {
290
        return cryption_phpCrypt($message, $sk, $iv, $type);
291
    }
292
}
293
294
/*
295
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
296
 *
297
 * Using AES_128 and mode CBC
298
 *
299
 * $key and $iv have to be given in hex format
300
 */
301
function cryption_phpCrypt($string, $key, $iv, $type)
302
{
303
    // manage key origin
304
    define('SALT', 'LEfzTjADMTzV6qHC');
305
306
    if ($key != SALT) {
307
        // check key (AES-128 requires a 16 bytes length key)
308
        if (strlen($key) < 16) {
309
            for ($x = strlen($key) + 1; $x <= 16; $x++) {
310
                $key .= chr(0);
311
            }
312
        } elseif (strlen($key) > 16) {
313
            $key = substr($key, 16);
314
        }
315
    }
316
317
    // load crypt
318
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
319
320
    if ($type == "encrypt") {
321
        // generate IV and encrypt
322
        $iv = $crypt->createIV();
323
        $encrypt = $crypt->encrypt($string);
324
        // return
325
        return array(
326
            "string" => bin2hex($encrypt),
327
            "iv" => bin2hex($iv),
328
            "error" => empty($encrypt) ? "ERR_ENCRYPTION_NOT_CORRECT" : ""
329
        );
330
    } elseif ($type == "decrypt") {
331
        // case if IV is empty
332
        if (empty($iv)) {
333
                    return array(
334
                'string' => "",
335
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
336
            );
337
        }
338
339
        // convert
340
        try {
341
            $string = testHex2Bin(trim($string));
342
            $iv = testHex2Bin($iv);
343
        } catch (Exception $e) {
344
            return array(
345
                'string' => "",
346
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
347
            );
348
        }
349
350
        // load IV
351
        $crypt->IV($iv);
352
        // decrypt
353
        $decrypt = $crypt->decrypt($string);
354
        // return
355
        return array(
356
            'string' => str_replace(chr(0), "", $decrypt),
357
            'error' => ""
358
        );
359
    }
360
}
361
362
function testHex2Bin($val)
363
{
364
    if (!@hex2bin($val)) {
365
        throw new Exception("ERROR");
366
    }
367
    return hex2bin($val);
368
}
369
370
/**
371
 * @param string $ascii_key
372
 * @param string $type
373
 */
374
function cryption($message, $ascii_key, $type) //defuse_crypto
375
{
376
    global $SETTINGS;
377
378
    // load PhpEncryption library
379 View Code Duplication
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
380
        $path = '../includes/libraries/Encryption/Encryption/';
381
    } else {
382
        $path = $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
383
    }
384
385
    require_once $path.'Crypto.php';
386
    require_once $path.'Encoding.php';
387
    require_once $path.'DerivedKeys.php';
388
    require_once $path.'Key.php';
389
    require_once $path.'KeyOrPassword.php';
390
    require_once $path.'File.php';
391
    require_once $path.'RuntimeTests.php';
392
    require_once $path.'KeyProtectedByPassword.php';
393
    require_once $path.'Core.php';
394
395
    // init
396
    $err = '';
397
    if (empty($ascii_key)) {
398
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
399
    }
400
401
    // convert KEY
402
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
403
404
    try {
405
        if ($type === "encrypt") {
406
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
407
        } elseif ($type === "decrypt") {
408
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
409
        }
410
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
411
        $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.";
412
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
413
        $err = $ex;
414
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
415
        $err = $ex;
416
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
417
        $err = $ex;
418
    } catch (Defuse\Crypto\Exception\IOException $ex) {
419
        $err = $ex;
420
    }
421
422
    return array(
423
        'string' => isset($text) ? $text : "",
424
        'error' => $err
425
    );
426
}
427
428
function defuse_generate_key()
429
{
430
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
431
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
432
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
433
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
434
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
435
    require_once '../includes/libraries/Encryption/Encryption/File.php';
436
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
437
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
438
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
439
440
    $key = \Defuse\Crypto\Key::createNewRandomKey();
441
    $key = $key->saveToAsciiSafeString();
442
    return $key;
443
}
444
445
function defuse_generate_personal_key($psk)
446
{
447
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
448
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
449
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
450
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
451
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
452
    require_once '../includes/libraries/Encryption/Encryption/File.php';
453
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
454
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
455
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
456
457
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
458
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
459
460
    return $protected_key_encoded; // save this in user table
461
}
462
463
/**
464
 * @param string $psk
465
 */
466
function defuse_validate_personal_key($psk, $protected_key_encoded)
467
{
468
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
469
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
470
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
471
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
472
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
473
    require_once '../includes/libraries/Encryption/Encryption/File.php';
474
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
475
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
476
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
477
478
    try {
479
        $protected_key = \Defuse\Crypto\KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
480
        $user_key = $protected_key->unlockKey($psk);
481
        $user_key_encoded = $user_key->saveToAsciiSafeString();
482
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
483
        return "Error - Major issue as the encryption is broken.";
484
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
485
        return "Error - The saltkey is not the correct one.";
486
    }
487
488
    return $user_key_encoded; // store it in session once user has entered his psk
489
}
490
491
/**
492
 * trimElement()
493
 *
494
 * trim a string depending on a specific string
495
 * @param string $element
496
 * @return string
497
 */
498
function trimElement($chaine, $element)
499
{
500
    if (!empty($chaine)) {
501
        $chaine = trim($chaine);
502
        if (substr($chaine, 0, 1) == $element) {
503
            $chaine = substr($chaine, 1);
504
        }
505
        if (substr($chaine, strlen($chaine) - 1, 1) == $element) {
506
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
507
        }
508
    }
509
    return $chaine;
510
}
511
512
/**
513
 * cleanString()
514
 *
515
 * permits to suppress all "special" characters from string
516
 */
517
function cleanString($string, $special = false)
518
{
519
    // Create temporary table for special characters escape
520
    $tabSpecialChar = array();
521
    for ($i = 0; $i <= 31; $i++) {
522
        $tabSpecialChar[] = chr($i);
523
    }
524
    array_push($tabSpecialChar, "<br />");
525
    if ($special == "1") {
526
        $tabSpecialChar = array_merge($tabSpecialChar, array("</li>", "<ul>", "<ol>"));
527
    }
528
529
    return str_replace($tabSpecialChar, "\n", $string);
530
}
531
532
function db_error_handler($params)
533
{
534
    echo "Error: ".$params['error']."<br>\n";
535
    echo "Query: ".$params['query']."<br>\n";
536
    throw new Exception("Error - Query", 1);
537
}
538
539
/**
540
 * [identifyUserRights description]
541
 * @param  string $groupesVisiblesUser  [description]
542
 * @param  string $groupesInterditsUser [description]
543
 * @param  string $isAdmin              [description]
544
 * @param  string $idFonctions          [description]
545
 * @return string                       [description]
546
 */
547
function identifyUserRights($groupesVisiblesUser, $groupesInterditsUser, $isAdmin, $idFonctions)
548
{
549
    global $server, $user, $pass, $database, $port, $encoding;
550
    global $SETTINGS;
551
552
    //load ClassLoader
553
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
554
555
    //Connect to DB
556
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
557
    DB::$host = $server;
558
    DB::$user = $user;
559
    DB::$password = $pass;
560
    DB::$dbName = $database;
561
    DB::$port = $port;
562
    DB::$encoding = $encoding;
563
    DB::$error_handler = true;
564
    $link = mysqli_connect($server, $user, $pass, $database, $port);
565
    $link->set_charset($encoding);
566
567
    //Build tree
568
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
569
    $tree->register();
570
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
571
572
    // Check if user is ADMINISTRATOR
573
    if ($isAdmin == 1) {
574
        $groupesVisibles = array();
575
        $_SESSION['personal_folders'] = array();
576
        $_SESSION['groupes_visibles'] = array();
577
        $_SESSION['groupes_interdits'] = array();
578
        $_SESSION['personal_visible_groups'] = array();
579
        $_SESSION['read_only_folders'] = array();
580
        $_SESSION['list_restricted_folders_for_items'] = array();
581
        $_SESSION['list_folders_editable_by_role'] = array();
582
        $_SESSION['list_folders_limited'] = array();
583
        $_SESSION['groupes_visibles_list'] = "";
584
        $_SESSION['list_folders_limited'] = "";
585
        $rows = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i", 0);
586
        foreach ($rows as $record) {
587
            array_push($groupesVisibles, $record['id']);
588
        }
589
        $_SESSION['groupes_visibles'] = $groupesVisibles;
590
        $_SESSION['all_non_personal_folders'] = $groupesVisibles;
591
        // Exclude all PF
592
        $_SESSION['forbiden_pfs'] = array();
593
        $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
594
        $where->add('personal_folder=%i', 1);
595
        if (isset($SETTINGS['enable_pf_feature']) && $SETTINGS['enable_pf_feature'] == 1) {
596
            $where->add('title=%s', $_SESSION['user_id']);
597
            $where->negateLast();
598
        }
599
        // Get ID of personal folder
600
        $persfld = DB::queryfirstrow(
601
            "SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s",
602
            $_SESSION['user_id']
603
        );
604
        if (!empty($persfld['id'])) {
605
            if (!in_array($persfld['id'], $_SESSION['groupes_visibles'])) {
606
                array_push($_SESSION['groupes_visibles'], $persfld['id']);
607
                array_push($_SESSION['personal_visible_groups'], $persfld['id']);
608
                // get all descendants
609
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
610
                $tree->rebuild();
611
                $tst = $tree->getDescendants($persfld['id']);
612
                foreach ($tst as $t) {
613
                    array_push($_SESSION['groupes_visibles'], $t->id);
614
                    array_push($_SESSION['personal_visible_groups'], $t->id);
615
                }
616
            }
617
        }
618
619
        // get complete list of ROLES
620
        $tmp = explode(";", $_SESSION['fonction_id']);
621
        $rows = DB::query(
622
            "SELECT * FROM ".prefix_table("roles_title")."
623
            ORDER BY title ASC"
624
        );
625
        foreach ($rows as $record) {
626
            if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
627
                array_push($tmp, $record['id']);
628
            }
629
        }
630
        $_SESSION['fonction_id'] = implode(";", $tmp);
631
632
        $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
633
        $_SESSION['is_admin'] = $isAdmin;
634
        // Check if admin has created Folders and Roles
635
        DB::query("SELECT * FROM ".prefix_table("nested_tree")."");
636
        $_SESSION['nb_folders'] = DB::count();
637
        DB::query("SELECT * FROM ".prefix_table("roles_title"));
638
        $_SESSION['nb_roles'] = DB::count();
639
    } else {
640
        // init
641
        $_SESSION['groupes_visibles'] = array();
642
        $_SESSION['personal_folders'] = array();
643
        $_SESSION['groupes_interdits'] = array();
644
        $_SESSION['personal_visible_groups'] = array();
645
        $_SESSION['read_only_folders'] = array();
646
        $groupesInterdits = array();
647
        if (!is_array($groupesInterditsUser)) {
648
            $groupesInterditsUser = explode(';', trimElement($groupesInterditsUser, ";"));
649
        }
650
        if (!empty($groupesInterditsUser) && count($groupesInterditsUser) > 0) {
651
            $groupesInterdits = $groupesInterditsUser;
652
        }
653
        $_SESSION['is_admin'] = $isAdmin;
654
        $fonctionsAssociees = explode(';', trimElement($idFonctions, ";"));
655
656
        $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
657
658
        // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
659
        foreach ($fonctionsAssociees as $roleId) {
660
            if (!empty($roleId)) {
661
                // Get allowed folders for each Role
662
                $rows = DB::query("SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id=%i", $roleId);
663
664
                if (DB::count() > 0) {
665
                    $tmp = DB::queryfirstrow("SELECT allow_pw_change FROM ".prefix_table("roles_title")." WHERE id = %i", $roleId);
666
                    foreach ($rows as $record) {
667
                        if (isset($record['folder_id']) && !in_array($record['folder_id'], $listAllowedFolders)) {
668
                            array_push($listAllowedFolders, $record['folder_id']);
669
                        }
670
                        // Check if this group is allowed to modify any pw in allowed folders
671
                        if ($tmp['allow_pw_change'] == 1 && !in_array($record['folder_id'], $listFoldersEditableByRole)) {
672
                            array_push($listFoldersEditableByRole, $record['folder_id']);
673
                        }
674
                    }
675
                    // Check for the users roles if some specific rights exist on items
676
                    $rows = DB::query(
677
                        "SELECT i.id_tree, r.item_id
678
                        FROM ".prefix_table("items")." as i
679
                        INNER JOIN ".prefix_table("restriction_to_roles")." as r ON (r.item_id=i.id)
680
                        WHERE r.role_id=%i
681
                        ORDER BY i.id_tree ASC",
682
                        $roleId
683
                    );
684
                    $x = 0;
685
                    foreach ($rows as $record) {
686
                        if (isset($record['id_tree'])) {
687
                            $listFoldersLimited[$record['id_tree']][$x] = $record['item_id'];
688
                            $x++;
689
                        }
690
                    }
691
                }
692
            }
693
        }
694
695
        // Does this user is allowed to see other items
696
        $x = 0;
697
        $rows = DB::query(
698
            "SELECT id, id_tree FROM ".prefix_table("items")."
699
            WHERE restricted_to LIKE %ss AND inactif=%s",
700
            $_SESSION['user_id'].';',
701
            '0'
702
        );
703
        foreach ($rows as $record) {
704
            $listRestrictedFoldersForItems[$record['id_tree']][$x] = $record['id'];
705
            $x++;
706
        }
707
        // => Build final lists
708
        // Clean arrays
709
        $listAllowedFolders = array_unique($listAllowedFolders);
710
        $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ";"));
711
        // Add user allowed folders
712
        $allowedFoldersTmp = array_unique(
713
            array_merge($listAllowedFolders, $groupesVisiblesUser)
714
        );
715
        // Exclude from allowed folders all the specific user forbidden folders
716
        $allowedFolders = array();
717
        foreach ($allowedFoldersTmp as $id) {
718
            if (!in_array($id, $groupesInterditsUser) && !empty($id)) {
719
                array_push($allowedFolders, $id);
720
            }
721
        }
722
723
        // Clean array
724
        $listAllowedFolders = array_filter(array_unique($allowedFolders));
725
726
        // Exclude all PF
727
        $_SESSION['forbiden_pfs'] = array();
728
729
        $where = new WhereClause('and');
730
        $where->add('personal_folder=%i', 1);
731
        if (isset($SETTINGS['enable_pf_feature']) &&
732
            $SETTINGS['enable_pf_feature'] == 1 &&
733
            isset($_SESSION['personal_folder']) &&
734
            $_SESSION['personal_folder'] == 1
735
        ) {
736
            $where->add('title=%s', $_SESSION['user_id']);
737
            $where->negateLast();
738
        }
739
740
        $pfs = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE %l", $where);
741
        foreach ($pfs as $pfId) {
742
            array_push($_SESSION['forbiden_pfs'], $pfId['id']);
743
        }
744
        // Get IDs of personal folders
745
        if (isset($SETTINGS['enable_pf_feature']) &&
746
            $SETTINGS['enable_pf_feature'] == 1 &&
747
            isset($_SESSION['personal_folder']) &&
748
            $_SESSION['personal_folder'] == 1
749
        ) {
750
            $pf = DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s", $_SESSION['user_id']);
751
            if (!empty($pf['id'])) {
752
                if (!in_array($pf['id'], $listAllowedFolders)) {
753
                    array_push($_SESSION['personal_folders'], $pf['id']);
754
                    // get all descendants
755
                    $ids = $tree->getDescendants($pf['id'], true, false);
756
                    foreach ($ids as $id) {
757
                        array_push($listAllowedFolders, $id->id);
758
                        array_push($_SESSION['personal_visible_groups'], $id->id);
759
                        array_push($_SESSION['personal_folders'], $id->id);
760
                    }
761
                }
762
            }
763
            // get list of readonly folders when pf is disabled.
764
            // rule - if one folder is set as W or N in one of the Role, then User has access as W
765
            foreach ($listAllowedFolders as $folderId) {
766
                if (!in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders'])))) {   //
767
                    DB::query(
768
                        "SELECT *
769
                        FROM ".prefix_table("roles_values")."
770
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
771
                        $folderId,
772
                        $fonctionsAssociees,
773
                        array("W", "ND", "NE", "NDNE")
774
                    );
775
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
776
                        array_push($listReadOnlyFolders, $folderId);
777
                    }
778
                }
779
            }
780
        } else {
781
            // get list of readonly folders when pf is disabled.
782
            // rule - if one folder is set as W in one of the Role, then User has access as W
783
            foreach ($listAllowedFolders as $folderId) {
784
                if (!in_array($folderId, $listReadOnlyFolders)) {
785
                    DB::query(
786
                        "SELECT *
787
                        FROM ".prefix_table("roles_values")."
788
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
789
                        $folderId,
790
                        $fonctionsAssociees,
791
                        array("W", "ND", "NE", "NDNE")
792
                    );
793
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
794
                        array_push($listReadOnlyFolders, $folderId);
795
                    }
796
                }
797
            }
798
        }
799
800
        // check if change proposals on User's items
801
        if (isset($SETTINGS['enable_suggestion']) && $SETTINGS['enable_suggestion'] == 1) {
802
            DB::query(
803
                "SELECT *
804
                FROM ".prefix_table("items_change")." AS c
805
                LEFT JOIN ".prefix_table("log_items")." AS i ON (c.item_id = i.id_item)
806
                WHERE i.action = %s AND i.id_user = %i",
807
                "at_creation",
808
                $_SESSION['user_id']
809
            );
810
            $_SESSION['nb_item_change_proposals'] = DB::count();
811
        } else {
812
            $_SESSION['nb_item_change_proposals'] = 0;
813
        }
814
815
        $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
816
        $_SESSION['groupes_visibles'] = $listAllowedFolders;
817
        $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
818
        $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
819
        $_SESSION['read_only_folders'] = $listReadOnlyFolders;
820
        $_SESSION['no_access_folders'] = $groupesInterdits;
821
822
        $_SESSION['list_folders_limited'] = $listFoldersLimited;
823
        $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
824
        $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
825
        // Folders and Roles numbers
826
        DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")."");
827
        $_SESSION['nb_folders'] = DB::count();
828
        DB::queryfirstrow("SELECT id FROM ".prefix_table("roles_title"));
829
        $_SESSION['nb_roles'] = DB::count();
830
    }
831
832
    // update user's timestamp
833
    DB::update(
834
        prefix_table('users'),
835
        array(
836
            'timestamp' => time()
837
        ),
838
        "id=%i",
839
        $_SESSION['user_id']
840
    );
841
}
842
843
/**
844
 * updateCacheTable()
845
 *
846
 * Update the CACHE table
847
 * @param string $action
848
 */
849
function updateCacheTable($action, $id = "")
850
{
851
    global $server, $user, $pass, $database, $port, $encoding;
852
    global $SETTINGS;
853
854
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
855
856
    //Connect to DB
857
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
858
    DB::$host = $server;
859
    DB::$user = $user;
860
    DB::$password = $pass;
861
    DB::$dbName = $database;
862
    DB::$port = $port;
863
    DB::$encoding = $encoding;
864
    DB::$error_handler = true;
865
    $link = mysqli_connect($server, $user, $pass, $database, $port);
866
    $link->set_charset($encoding);
867
868
    //Load Tree
869
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
870
    $tree->register();
871
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
872
873
    // Rebuild full cache table
874
    if ($action === "reload") {
875
        // truncate table
876
        DB::query("TRUNCATE TABLE ".prefix_table("cache"));
877
878
        // reload date
879
        $rows = DB::query(
880
            "SELECT *
881
            FROM ".prefix_table('items')." as i
882
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
883
            AND l.action = %s
884
            AND i.inactif = %i",
885
            'at_creation',
886
            0
887
        );
888
        foreach ($rows as $record) {
889
            // Get all TAGS
890
            $tags = "";
891
            $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $record['id']);
892 View Code Duplication
            foreach ($itemTags as $itemTag) {
893
                if (!empty($itemTag['tag'])) {
894
                    $tags .= $itemTag['tag']." ";
895
                }
896
            }
897
            // Get renewal period
898
            $resNT = DB::queryfirstrow("SELECT renewal_period FROM ".prefix_table('nested_tree')." WHERE id=%i", $record['id_tree']);
899
900
            // form id_tree to full foldername
901
            $folder = "";
902
            $arbo = $tree->getPath($record['id_tree'], true);
903 View Code Duplication
            foreach ($arbo as $elem) {
904
                if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
905
                    $elem->title = $_SESSION['login'];
906
                }
907
                if (empty($folder)) {
908
                    $folder = stripslashes($elem->title);
909
                } else {
910
                    $folder .= " » ".stripslashes($elem->title);
911
                }
912
            }
913
            // store data
914
            DB::insert(
915
                prefix_table('cache'),
916
                array(
917
                    'id' => $record['id'],
918
                    'label' => $record['label'],
919
                    'description' => isset($record['description']) ? $record['description'] : "",
920
                    'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : "0",
921
                    'tags' => $tags,
922
                    'id_tree' => $record['id_tree'],
923
                    'perso' => $record['perso'],
924
                    'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : "0",
925
                    'login' => isset($record['login']) ? $record['login'] : "",
926
                    'folder' => $folder,
927
                    'author' => $record['id_user'],
928
                    'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : "0",
929
                    'timestamp' => $record['date']
930
                    )
931
            );
932
        }
933
        // UPDATE an item
934
    } elseif ($action === "update_value") {
935
        // get new value from db
936
        $data = DB::queryfirstrow(
937
            "SELECT label, description, id_tree, perso, restricted_to, login, url
938
            FROM ".prefix_table('items')."
939
            WHERE id=%i",
940
            $id
941
        );
942
        // Get all TAGS
943
        $tags = "";
944
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $id);
945 View Code Duplication
        foreach ($itemTags as $itemTag) {
946
            if (!empty($itemTag['tag'])) {
947
                $tags .= $itemTag['tag']." ";
948
            }
949
        }
950
        // form id_tree to full foldername
951
        $folder = "";
952
        $arbo = $tree->getPath($data['id_tree'], true);
953 View Code Duplication
        foreach ($arbo as $elem) {
954
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
955
                $elem->title = $_SESSION['login'];
956
            }
957
            if (empty($folder)) {
958
                $folder = stripslashes($elem->title);
959
            } else {
960
                $folder .= " » ".stripslashes($elem->title);
961
            }
962
        }
963
        // finaly update
964
        DB::update(
965
            prefix_table('cache'),
966
            array(
967
                'label' => $data['label'],
968
                'description' => $data['description'],
969
                'tags' => $tags,
970
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
971
                'id_tree' => $data['id_tree'],
972
                'perso' => $data['perso'],
973
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
974
                'login' => isset($data['login']) ? $data['login'] : "",
975
                'folder' => $folder,
976
                'author' => $_SESSION['user_id'],
977
                ),
978
            "id = %i",
979
            $id
980
        );
981
        // ADD an item
982
    } elseif ($action === "add_value") {
983
        // get new value from db
984
        $data = DB::queryFirstRow(
985
            "SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
986
            FROM ".prefix_table('items')." as i
987
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
988
            WHERE i.id = %i
989
            AND l.action = %s",
990
            $id,
991
            'at_creation'
992
        );
993
        // Get all TAGS
994
        $tags = "";
995
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id = %i", $id);
996 View Code Duplication
        foreach ($itemTags as $itemTag) {
997
            if (!empty($itemTag['tag'])) {
998
                $tags .= $itemTag['tag']." ";
999
            }
1000
        }
1001
        // form id_tree to full foldername
1002
        $folder = "";
1003
        $arbo = $tree->getPath($data['id_tree'], true);
1004 View Code Duplication
        foreach ($arbo as $elem) {
1005
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1006
                $elem->title = $_SESSION['login'];
1007
            }
1008
            if (empty($folder)) {
1009
                $folder = stripslashes($elem->title);
1010
            } else {
1011
                $folder .= " » ".stripslashes($elem->title);
1012
            }
1013
        }
1014
        // finaly update
1015
        DB::insert(
1016
            prefix_table('cache'),
1017
            array(
1018
                'id' => $data['id'],
1019
                'label' => $data['label'],
1020
                'description' => $data['description'],
1021
                'tags' => (isset($tags) && !empty($tags)) ? $tags : "None",
1022
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1023
                'id_tree' => $data['id_tree'],
1024
                'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== "None") ? $data['perso'] : "0",
1025
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "None",
1026
                'login' => isset($data['login']) ? $data['login'] : "",
1027
                'folder' => $folder,
1028
                'author' => $_SESSION['user_id'],
1029
                'timestamp' => $data['date']
1030
            )
1031
        );
1032
1033
        // DELETE an item
1034
    } elseif ($action === "delete_value") {
1035
        DB::delete(prefix_table('cache'), "id = %i", $id);
1036
    }
1037
}
1038
1039
/*
1040
*
1041
*/
1042
function getStatisticsData()
1043
{
1044
    global $SETTINGS;
1045
1046
    DB::query(
1047
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1048
        0
1049
    );
1050
    $counter_folders = DB::count();
1051
1052
    DB::query(
1053
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1054
        1
1055
    );
1056
    $counter_folders_perso = DB::count();
1057
1058
    DB::query(
1059
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1060
        0
1061
    );
1062
    $counter_items = DB::count();
1063
1064
    DB::query(
1065
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1066
        1
1067
    );
1068
    $counter_items_perso = DB::count();
1069
1070
    DB::query(
1071
        "SELECT id FROM ".prefix_table("users").""
1072
    );
1073
    $counter_users = DB::count();
1074
1075
    DB::query(
1076
        "SELECT id FROM ".prefix_table("users")." WHERE admin = %i",
1077
        1
1078
    );
1079
    $admins = DB::count();
1080
1081
    DB::query(
1082
        "SELECT id FROM ".prefix_table("users")." WHERE gestionnaire = %i",
1083
        1
1084
    );
1085
    $managers = DB::count();
1086
1087
    DB::query(
1088
        "SELECT id FROM ".prefix_table("users")." WHERE read_only = %i",
1089
        1
1090
    );
1091
    $ro = DB::count();
1092
1093
    // list the languages
1094
    $usedLang = [];
1095
    $tp_languages = DB::query(
1096
        "SELECT name FROM ".prefix_table("languages")
1097
    );
1098
    foreach ($tp_languages as $tp_language) {
1099
        DB::query(
1100
            "SELECT * FROM ".prefix_table("users")." WHERE user_language = %s",
1101
            $tp_language['name']
1102
        );
1103
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1104
    }
1105
1106
    // get list of ips
1107
    $usedIp = [];
1108
    $tp_ips = DB::query(
1109
        "SELECT user_ip FROM ".prefix_table("users")
1110
    );
1111
    foreach ($tp_ips as $ip) {
1112
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1113
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1114
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== "none") {
1115
            $usedIp[$ip['user_ip']] = 1;
1116
        }
1117
    }
1118
1119
    return array(
1120
        "error" => "",
1121
        "stat_phpversion" => phpversion(),
1122
        "stat_folders" => $counter_folders,
1123
        "stat_folders_shared" => intval($counter_folders) - intval($counter_folders_perso),
1124
        "stat_items" => $counter_items,
1125
        "stat_items_shared" => intval($counter_items) - intval($counter_items_perso),
1126
        "stat_users" => $counter_users,
1127
        "stat_admins" => $admins,
1128
        "stat_managers" => $managers,
1129
        "stat_ro" => $ro,
1130
        "stat_kb" => $SETTINGS['enable_kb'],
1131
        "stat_pf" => $SETTINGS['enable_pf_feature'],
1132
        "stat_fav" => $SETTINGS['enable_favourites'],
1133
        "stat_teampassversion" => $SETTINGS['cpassman_version'],
1134
        "stat_ldap" => $SETTINGS['ldap_mode'],
1135
        "stat_agses" => $SETTINGS['agses_authentication_enabled'],
1136
        "stat_duo" => $SETTINGS['duo'],
1137
        "stat_suggestion" => $SETTINGS['enable_suggestion'],
1138
        "stat_api" => $SETTINGS['api'],
1139
        "stat_customfields" => $SETTINGS['item_extra_fields'],
1140
        "stat_syslog" => $SETTINGS['syslog_enable'],
1141
        "stat_2fa" => $SETTINGS['google_authentication'],
1142
        "stat_stricthttps" => $SETTINGS['enable_sts'],
1143
        "stat_mysqlversion" => DB::serverVersion(),
1144
        "stat_languages" => $usedLang,
1145
        "stat_country" => $usedIp
1146
    );
1147
}
1148
1149
/**
1150
 * sendEmail()
1151
 *
1152
 * @return
1153
 */
1154
function sendEmail($subject, $textMail, $email, $textMailAlt = "")
1155
{
1156
    global $LANG;
1157
    global $SETTINGS;
1158
1159
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
1160
    //load library
1161
    $user_language = isset($_SESSION['user_language']) ? $_SESSION['user_language'] : "english";
1162
    require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1163
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Email/Phpmailer/PHPMailerAutoload.php';
1164
1165
    // load PHPMailer
1166
    $mail = new PHPMailer();
1167
1168
    // send to user
1169
    $mail->setLanguage("en", "../includes/libraries/Email/Phpmailer/language/");
1170
    $mail->SMTPDebug = 0; //value 1 can be used to debug
1171
    $mail->Port = $SETTINGS['email_port']; //COULD BE USED
1172
    $mail->CharSet = "utf-8";
1173
    $smtp_security = $SETTINGS['email_security'];
1174
    if ($smtp_security == "tls" || $smtp_security == "ssl") {
1175
        $mail->SMTPSecure = $smtp_security;
1176
    }
1177
    $mail->isSmtp(); // send via SMTP
1178
    $mail->Host = $SETTINGS['email_smtp_server']; // SMTP servers
1179
    $mail->SMTPAuth = $SETTINGS['email_smtp_auth'] == '1' ? true : false; // turn on SMTP authentication
1180
    $mail->Username = $SETTINGS['email_auth_username']; // SMTP username
1181
    $mail->Password = $SETTINGS['email_auth_pwd']; // SMTP password
1182
    $mail->From = $SETTINGS['email_from'];
1183
    $mail->FromName = $SETTINGS['email_from_name'];
1184
    $mail->addAddress($email); //Destinataire
1185
    $mail->WordWrap = 80; // set word wrap
1186
    $mail->isHtml(true); // send as HTML
1187
    $mail->Subject = $subject;
1188
    $mail->Body = $textMail;
1189
    $mail->AltBody = $textMailAlt;
1190
    // send email
1191
    if (!$mail->send()) {
1192
        return '"error":"error_mail_not_send" , "message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1193
    } else {
1194
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1195
    }
1196
}
1197
1198
/**
1199
 * generateKey()
1200
 *
1201
 * @return
1202
 */
1203
function generateKey()
1204
{
1205
    return substr(md5(rand().rand()), 0, 15);
1206
}
1207
1208
/**
1209
 * dateToStamp()
1210
 *
1211
 * @return
1212
 */
1213
function dateToStamp($date)
1214
{
1215
    $date = date_parse_from_format($SETTINGS['date_format'], $date);
0 ignored issues
show
Bug introduced by
The variable $SETTINGS does not exist. Did you forget to declare it?

This check marks access to variables or properties that have not been declared yet. While PHP has no explicit notion of declaring a variable, accessing it before a value is assigned to it is most likely a bug.

Loading history...
1216
    if ($date['warning_count'] == 0 && $date['error_count'] == 0) {
1217
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1218
    } else {
1219
        return false;
1220
    }
1221
}
1222
1223
function isDate($date)
1224
{
1225
    return (strtotime($date) !== false);
1226
}
1227
1228
/**
1229
 * isUTF8()
1230
 *
1231
 * @return integer is the string in UTF8 format.
1232
 */
1233
1234
function isUTF8($string)
1235
{
1236
    if (is_array($string) === true) {
1237
        $string = $string['string'];
1238
    }
1239
    return preg_match(
1240
        '%^(?:
1241
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1242
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1243
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1244
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1245
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1246
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1247
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1248
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1249
        )*$%xs',
1250
        $string
1251
    );
1252
}
1253
1254
/*
1255
* FUNCTION
1256
* permits to prepare data to be exchanged
1257
*/
1258
/**
1259
 * @param string $type
1260
 */
1261
function prepareExchangedData($data, $type)
1262
{
1263
    global $SETTINGS;
1264
1265
    //load ClassLoader
1266
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1267
    //Load AES
1268
    $aes = new SplClassLoader('Encryption\Crypt', '../includes/libraries');
1269
    $aes->register();
1270
1271
    if ($type == "encode") {
1272
        if (isset($SETTINGS['encryptClientServer'])
1273
            && $SETTINGS['encryptClientServer'] === "0"
1274
        ) {
1275
            return json_encode(
1276
                $data,
1277
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1278
            );
1279
        } else {
1280
            return Encryption\Crypt\aesctr::encrypt(
1281
                json_encode(
1282
                    $data,
1283
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1284
                ),
1285
                $_SESSION['key'],
1286
                256
1287
            );
1288
        }
1289
    } elseif ($type == "decode") {
1290
        if (isset($SETTINGS['encryptClientServer'])
1291
            && $SETTINGS['encryptClientServer'] === "0"
1292
        ) {
1293
            return json_decode(
1294
                $data,
1295
                true
1296
            );
1297
        } else {
1298
            return json_decode(
1299
                Encryption\Crypt\aesctr::decrypt(
1300
                    $data,
1301
                    $_SESSION['key'],
1302
                    256
1303
                ),
1304
                true
1305
            );
1306
        }
1307
    }
1308
}
1309
1310
function make_thumb($src, $dest, $desired_width)
1311
{
1312
    /* read the source image */
1313
    $source_image = imagecreatefrompng($src);
1314
    $width = imagesx($source_image);
1315
    $height = imagesy($source_image);
1316
1317
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1318
    $desired_height = floor($height * ($desired_width / $width));
1319
1320
    /* create a new, "virtual" image */
1321
    $virtual_image = imagecreatetruecolor($desired_width, $desired_height);
1322
1323
    /* copy source image at a resized size */
1324
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
1325
1326
    /* create the physical thumbnail image to its destination */
1327
    imagejpeg($virtual_image, $dest);
1328
}
1329
1330
/*
1331
** check table prefix in SQL query
1332
*/
1333
/**
1334
 * @param string $table
1335
 */
1336
function prefix_table($table)
1337
{
1338
    global $pre;
1339
    $safeTable = htmlspecialchars($pre.$table);
1340
    if (!empty($safeTable)) {
1341
        // sanitize string
1342
        return $safeTable;
1343
    } else {
1344
        // stop error no table
1345
        return "table_not_exists";
1346
    }
1347
}
1348
1349
/*
1350
 * Creates a KEY using PasswordLib
1351
 */
1352
function GenerateCryptKey($size = "", $secure = false, $numerals = false, $capitalize = false, $ambiguous = false, $symbols = false)
1353
{
1354
    // load library
1355
    $pwgen = new SplClassLoader('Encryption\PwGen', '../includes/libraries');
1356
    $pwgen->register();
1357
    $pwgen = new Encryption\PwGen\pwgen();
1358
1359
    // init
1360
    if (!empty($size)) {
1361
        $pwgen->setLength($size);
1362
    }
1363
    if (!empty($secure)) {
1364
        $pwgen->setSecure($secure);
1365
    }
1366
    if (!empty($numerals)) {
1367
        $pwgen->setNumerals($numerals);
1368
    }
1369
    if (!empty($capitalize)) {
1370
        $pwgen->setCapitalize($capitalize);
1371
    }
1372
    if (!empty($ambiguous)) {
1373
        $pwgen->setAmbiguous($ambiguous);
1374
    }
1375
    if (!empty($symbols)) {
1376
        $pwgen->setSymbols($symbols);
1377
    }
1378
1379
    // generate and send back
1380
    return $pwgen->generate();
1381
}
1382
1383
/*
1384
* Send sysLOG message
1385
* @param string $message
1386
* @param string $host
1387
*/
1388
function send_syslog($message, $host, $port, $component = "teampass")
1389
{
1390
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1391
        //$syslog_message = "<123>" . date('M d H:i:s ') . " " .$host . " " . $component . ": " . $message;
1392
    $syslog_message = "<123>".date('M d H:i:s ').$component.": ".$message;
1393
        socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1394
    socket_close($sock);
1395
}
1396
1397
1398
1399
/**
1400
 * logEvents()
1401
 *
1402
 * permits to log events into DB
1403
 * @param string $type
1404
 * @param string $label
1405
 * @param string $field_1
1406
 */
1407
function logEvents($type, $label, $who, $login = "", $field_1 = null)
1408
{
1409
    global $server, $user, $pass, $database, $port, $encoding;
1410
    global $SETTINGS;
1411
1412
    if (empty($who)) {
1413
        $who = get_client_ip_server();
1414
    }
1415
1416
    // include librairies & connect to DB
1417
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1418
    DB::$host = $server;
1419
    DB::$user = $user;
1420
    DB::$password = $pass;
1421
    DB::$dbName = $database;
1422
    DB::$port = $port;
1423
    DB::$encoding = $encoding;
1424
    DB::$error_handler = true;
1425
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1426
    $link->set_charset($encoding);
1427
1428
    DB::insert(
1429
        prefix_table("log_system"),
1430
        array(
1431
            'type' => $type,
1432
            'date' => time(),
1433
            'label' => $label,
1434
            'qui' => $who,
1435
            'field_1' => $field_1 === null ? "" : $field_1
1436
        )
1437
    );
1438
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1439
        if ($type == "user_mngt") {
1440
            send_syslog(
1441
                "The User ".$login." perform the acction off ".$label." to the user ".$field_1." - ".$type,
1442
                $SETTINGS['syslog_host'],
1443
                $SETTINGS['syslog_port'],
1444
                "teampass"
1445
            );
1446
        } else {
1447
            send_syslog(
1448
                "The User ".$login." perform the acction off ".$label." - ".$type,
1449
                $SETTINGS['syslog_host'],
1450
                $SETTINGS['syslog_port'],
1451
                "teampass"
1452
            );
1453
        }
1454
    }
1455
}
1456
1457
/**
1458
 * @param string $item
1459
 * @param string $action
1460
 */
1461
function logItems($id, $item, $id_user, $action, $login = "", $raison = null, $raison_iv = null, $encryption_type = "")
1462
{
1463
    global $server, $user, $pass, $database, $port, $encoding;
1464
    global $SETTINGS;
1465
1466
    // include librairies & connect to DB
1467
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1468
    DB::$host = $server;
1469
    DB::$user = $user;
1470
    DB::$password = $pass;
1471
    DB::$dbName = $database;
1472
    DB::$port = $port;
1473
    DB::$encoding = $encoding;
1474
    DB::$error_handler = true;
1475
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1476
    $link->set_charset($encoding);
1477
    DB::insert(
1478
        prefix_table("log_items"),
1479
        array(
1480
            'id_item' => $id,
1481
            'date' => time(),
1482
            'id_user' => $id_user,
1483
            'action' => $action,
1484
            'raison' => $raison,
1485
            'raison_iv' => $raison_iv,
1486
            'encryption_type' => $encryption_type
1487
        )
1488
    );
1489
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1490
        send_syslog(
1491
            "The Item ".$item." was ".$action." by ".$login." ".$raison,
1492
            $SETTINGS['syslog_host'],
1493
            $SETTINGS['syslog_port'],
1494
            "teampass"
1495
        );
1496
    }
1497
}
1498
1499
/*
1500
* Function to get the client ip address
1501
 */
1502
function get_client_ip_server()
1503
{
1504
    if (getenv('HTTP_CLIENT_IP')) {
1505
            $ipaddress = getenv('HTTP_CLIENT_IP');
1506
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1507
            $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1508
    } elseif (getenv('HTTP_X_FORWARDED')) {
1509
            $ipaddress = getenv('HTTP_X_FORWARDED');
1510
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1511
            $ipaddress = getenv('HTTP_FORWARDED_FOR');
1512
    } elseif (getenv('HTTP_FORWARDED')) {
1513
            $ipaddress = getenv('HTTP_FORWARDED');
1514
    } elseif (getenv('REMOTE_ADDR')) {
1515
            $ipaddress = getenv('REMOTE_ADDR');
1516
    } else {
1517
            $ipaddress = 'UNKNOWN';
1518
    }
1519
1520
    return $ipaddress;
1521
}
1522
1523
/**
1524
 * Escape all HTML, JavaScript, and CSS
1525
 *
1526
 * @param string $input The input string
1527
 * @param string $encoding Which character encoding are we using?
1528
 * @return string
1529
 */
1530
function noHTML($input, $encoding = 'UTF-8')
1531
{
1532
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1533
}
1534
1535
/**
1536
 * handleConfigFile()
1537
 *
1538
 * permits to handle the Teampass config file
1539
 * $action accepts "rebuild" and "update"
1540
 */
1541
function handleConfigFile($action, $field = null, $value = null)
1542
{
1543
    global $server, $user, $pass, $database, $port, $encoding;
1544
    global $SETTINGS;
1545
1546
    $tp_config_file = "../includes/config/tp.config.php";
1547
1548
    // Load AntiXSS
1549
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXss.php';
1550
    $antiXss = new protect\AntiXSS\AntiXSS();
1551
1552
    // include librairies & connect to DB
1553
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1554
    DB::$host = $server;
1555
    DB::$user = $user;
1556
    DB::$password = $pass;
1557
    DB::$dbName = $database;
1558
    DB::$port = $port;
1559
    DB::$encoding = $encoding;
1560
    DB::$error_handler = true;
1561
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1562
    $link->set_charset($encoding);
1563
1564
    if (!file_exists($tp_config_file) || $action == "rebuild") {
1565
        // perform a copy
1566
        if (file_exists($tp_config_file)) {
1567
            if (!copy($tp_config_file, $tp_config_file.'.'.date("Y_m_d_His", time()))) {
1568
                return "ERROR: Could not copy file '".$tp_config_file."'";
1569
            }
1570
        }
1571
1572
        // regenerate
1573
        $data = array();
1574
        $data[0] = "<?php\n";
1575
        $data[1] = "global \$SETTINGS;\n";
1576
        $data[2] = "\$SETTINGS = array (\n";
1577
        $rows = DB::query(
1578
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s",
1579
            "admin"
1580
        );
1581
        foreach ($rows as $record) {
1582
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
1583
        }
1584
        array_push($data, ");");
1585
        $data = array_unique($data);
1586
    } elseif ($action == "update" && !empty($field)) {
1587
        $data = file($tp_config_file);
1588
        $x = 0;
1589
        $bFound = false;
1590
        foreach ($data as $line) {
1591
            if (stristr($line, ");")) {
1592
                break;
1593
            }
1594
1595
            //
1596
            if (stristr($line, "'".$field."' => '")) {
1597
                $data[$x] = "    '".$field."' => '".$antiXss->xss_clean($value)."',\n";
1598
                $bFound = true;
1599
                break;
1600
            }
1601
            $x++;
1602
        }
1603
        if ($bFound === false) {
1604
            $data[($x - 1)] = "    '".$field."' => '".$antiXss->xss_clean($value)."',\n";
1605
        }
1606
    }
1607
1608
    // update file
1609
    file_put_contents($tp_config_file, implode('', isset($data) ? $data : array()));
0 ignored issues
show
Security File Manipulation introduced by
implode('', isset($data) ? $data : array()) 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 $_POST
    in sources/admin.queries.php on line 1780
  2. Data is decoded by json_decode()
    in vendor/sources/main.functions.php on line 1294
  3. $dataReceived is assigned
    in sources/admin.queries.php on line 1780
  4. $dataReceived['field'] is passed to handleConfigFile()
    in sources/admin.queries.php on line 1881
  5. $data is assigned
    in sources/main.functions.php on line 1604
  6. isset($data) ? $data : array() is passed through implode()
    in sources/main.functions.php on line 1609

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...
1610
1611
    return true;
1612
}
1613
1614
/*
1615
** Permits to replace &#92; to permit correct display
1616
*/
1617
/**
1618
 * @param string $input
1619
 */
1620
function handleBackslash($input)
1621
{
1622
    return str_replace("&amp;#92;", "&#92;", $input);
1623
}
1624
1625
/*
1626
** Permits to loas settings
1627
*/
1628
function loadSettings()
1629
{
1630
    global $SETTINGS;
1631
1632
    /* LOAD CPASSMAN SETTINGS */
1633
    if (!isset($SETTINGS['loaded']) || $SETTINGS['loaded'] != 1) {
1634
        $SETTINGS['duplicate_folder'] = 0; //by default, this is set to 0;
1635
        $SETTINGS['duplicate_item'] = 0; //by default, this is set to 0;
1636
        $SETTINGS['number_of_used_pw'] = 5; //by default, this value is set to 5;
1637
        $settings = array();
1638
1639
        $rows = DB::query(
1640
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s_type OR type=%s_type2",
1641
            array(
1642
                'type' => "admin",
1643
                'type2' => "settings"
1644
            )
1645
        );
1646
        foreach ($rows as $record) {
1647
            if ($record['type'] == 'admin') {
1648
                $SETTINGS[$record['intitule']] = $record['valeur'];
1649
            } else {
1650
                $settings[$record['intitule']] = $record['valeur'];
1651
            }
1652
        }
1653
        $SETTINGS['loaded'] = 1;
1654
        $SETTINGS['default_session_expiration_time'] = 5;
1655
    }
1656
}
1657
1658
/*
1659
** check if folder has custom fields.
1660
** Ensure that target one also has same custom fields
1661
*/
1662
function checkCFconsistency($source_id, $target_id)
1663
{
1664
    $source_cf = array();
1665
    $rows = DB::QUERY(
1666
        "SELECT id_category
1667
        FROM ".prefix_table("categories_folders")."
1668
        WHERE id_folder = %i",
1669
        $source_id
1670
    );
1671
    foreach ($rows as $record) {
1672
        array_push($source_cf, $record['id_category']);
1673
    }
1674
1675
    $target_cf = array();
1676
    $rows = DB::QUERY(
1677
        "SELECT id_category
1678
        FROM ".prefix_table("categories_folders")."
1679
        WHERE id_folder = %i",
1680
        $target_id
1681
    );
1682
    foreach ($rows as $record) {
1683
        array_push($target_cf, $record['id_category']);
1684
    }
1685
1686
    $cf_diff = array_diff($source_cf, $target_cf);
1687
    if (count($cf_diff) > 0) {
1688
        return false;
1689
    }
1690
1691
    return true;
1692
}
1693
1694
/*
1695
*
1696
*/
1697
function encrypt_or_decrypt_file($filename_to_rework, $filename_status)
1698
{
1699
    global $server, $user, $pass, $database, $port, $encoding;
1700
    global $SETTINGS;
1701
1702
    // Include librairies & connect to DB
1703
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1704
    DB::$host = $server;
1705
    DB::$user = $user;
1706
    DB::$password = $pass;
1707
    DB::$dbName = $database;
1708
    DB::$port = $port;
1709
    DB::$encoding = $encoding;
1710
    DB::$error_handler = true;
1711
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1712
    $link->set_charset($encoding);
1713
1714
    // Get file info in DB
1715
    $fileInfo = DB::queryfirstrow(
1716
        "SELECT id FROM ".prefix_table("files")." WHERE file = %s",
1717
        filter_var($filename_to_rework, FILTER_SANITIZE_STRING)
1718
    );
1719
    if (empty($fileInfo['id']) === false) {
1720
        // Load PhpEncryption library
1721
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'Crypto.php';
1722
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'Encoding.php';
1723
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'DerivedKeys.php';
1724
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'Key.php';
1725
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'KeyOrPassword.php';
1726
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'File.php';
1727
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'RuntimeTests.php';
1728
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'KeyProtectedByPassword.php';
1729
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'Core.php';
1730
1731
        // Get KEY
1732
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
1733
1734
        if (isset($SETTINGS['enable_attachment_encryption']) && $SETTINGS['enable_attachment_encryption'] === "1" && isset($filename_status) && ($filename_status === "clear" || $filename_status === "0")) {
1735
            // File needs to be encrypted
1736 View Code Duplication
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1737
                // Make a copy of file
1738
                if (!copy(
1739
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1740
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1741
                )) {
1742
                    exit;
1743
                } else {
1744
                    // Do a bck
1745
                    copy(
1746
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1747
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1748
                    );
1749
                }
1750
1751
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1752
1753
                // Now encrypt the file with saltkey
1754
                $err = '';
1755
                try {
1756
                    \Defuse\Crypto\File::encryptFile(
1757
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1758
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1759
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1760
                    );
1761
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1762
                    $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.";
1763
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1764
                    $err = $ex;
1765
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1766
                    $err = $ex;
1767
                }
1768
                if (empty($err) === false) {
1769
                    echo $err;
1770
                }
1771
1772
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1773
1774
                // update table
1775
                DB::update(
1776
                    prefix_table('files'),
1777
                    array(
1778
                        'status' => 'encrypted'
1779
                        ),
1780
                    "id = %i",
1781
                    $fileInfo['id']
1782
                );
1783
            }
1784
        } elseif (isset($SETTINGS['enable_attachment_encryption']) && $SETTINGS['enable_attachment_encryption'] === "0" && isset($filename_status) && $filename_status === "encrypted") {
1785
            // file needs to be decrypted
1786 View Code Duplication
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1787
                // make a copy of file
1788
                if (!copy(
1789
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1790
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1791
                )) {
1792
                    exit;
1793
                } else {
1794
                    // do a bck
1795
                    copy(
1796
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1797
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1798
                    );
1799
                }
1800
1801
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1802
1803
                // Now encrypt the file with saltkey
1804
                $err = '';
1805
                try {
1806
                    \Defuse\Crypto\File::decryptFile(
1807
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1808
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1809
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1810
                    );
1811
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1812
                    $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.";
1813
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1814
                    $err = $ex;
1815
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1816
                    $err = $ex;
1817
                }
1818
                if (empty($err) === false) {
1819
                    echo $err;
1820
                }
1821
1822
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1823
1824
                // update table
1825
                DB::update(
1826
                    prefix_table('files'),
1827
                    array(
1828
                        'status' => 'clear'
1829
                        ),
1830
                    "id = %i",
1831
                    $fileInfo['id']
1832
                );
1833
            }
1834
        }
1835
    }
1836
1837
    // Exit
1838
    return false;
1839
}
1840
1841
/**
1842
 * Will encrypte/decrypt a fil eusing Defuse
1843
 * @param  string $type        can be either encrypt or decrypt
1844
 * @param  string $source_file path to source file
1845
 * @param  string $target_file path to target file
1846
 * @return string              'true' is success or error message
1847
 */
1848
function prepareFileWithDefuse($type, $source_file, $target_file, $password = '')
1849
{
1850
    global $SETTINGS;
1851
1852
    // Load AntiXSS
1853
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXss.php';
1854
    $antiXss = new protect\AntiXSS\AntiXSS();
1855
1856
    // Protect against bad inputs
1857
    if (is_array($source_file) ||is_array($target_file)) {
1858
        return 'error_cannot_be_array';
1859
    }
1860
1861
    // Sanitize
1862
    $source_file = $antiXss->xss_clean($source_file);
1863
    $target_file = $antiXss->xss_clean($target_file);
1864
1865
    // load PhpEncryption library
1866
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'Crypto.php';
1867
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'Encoding.php';
1868
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'DerivedKeys.php';
1869
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'Key.php';
1870
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'KeyOrPassword.php';
1871
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'File.php';
1872
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'RuntimeTests.php';
1873
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'KeyProtectedByPassword.php';
1874
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/'.'Core.php';
1875
1876
    if (empty($password) === true) {
1877
    /*
1878
    File encryption/decryption is done with the SALTKEY
1879
     */
1880
1881
        // get KEY
1882
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
1883
1884
        // Now perform action on the file
1885
        $err = '';
1886 View Code Duplication
        if ($type === 'decrypt') {
1887
            try {
1888
                \Defuse\Crypto\File::decryptFile(
1889
                    $source_file,
0 ignored issues
show
Bug introduced by
It seems like $source_file defined by $antiXss->xss_clean($source_file) on line 1862 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...
1890
                    $target_file,
0 ignored issues
show
Bug introduced by
It seems like $target_file defined by $antiXss->xss_clean($target_file) on line 1863 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...
1891
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1892
                );
1893
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1894
                $err = "decryption_not_possible";
1895
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1896
                $err = $ex;
1897
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1898
                $err = $ex;
1899
            }
1900
        } elseif ($type === 'encrypt') {
1901
            try {
1902
                \Defuse\Crypto\File::encryptFile(
1903
                    $source_file,
0 ignored issues
show
Bug introduced by
It seems like $source_file defined by $antiXss->xss_clean($source_file) on line 1862 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...
1904
                    $target_file,
0 ignored issues
show
Bug introduced by
It seems like $target_file defined by $antiXss->xss_clean($target_file) on line 1863 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...
1905
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1906
                );
1907
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1908
                $err = "encryption_not_possible";
1909
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1910
                $err = $ex;
1911
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1912
                $err = $ex;
1913
            }
1914
        }
1915
    } else {
1916
    /*
1917
    File encryption/decryption is done with special password and not the SALTKEY
1918
     */
1919
1920
        $err = '';
1921 View Code Duplication
        if ($type === 'decrypt') {
1922
            try {
1923
                \Defuse\Crypto\File::decryptFileWithPassword(
1924
                    $source_file,
0 ignored issues
show
Bug introduced by
It seems like $source_file defined by $antiXss->xss_clean($source_file) on line 1862 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...
1925
                    $target_file,
0 ignored issues
show
Bug introduced by
It seems like $target_file defined by $antiXss->xss_clean($target_file) on line 1863 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...
1926
                    $password
1927
                );
1928
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1929
                $err = "wrong_key";
1930
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1931
                $err = $ex;
1932
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1933
                $err = $ex;
1934
            }
1935
        } elseif ($type === 'encrypt') {
1936
            try {
1937
                \Defuse\Crypto\File::encryptFileWithPassword(
1938
                    $source_file,
0 ignored issues
show
Bug introduced by
It seems like $source_file defined by $antiXss->xss_clean($source_file) on line 1862 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...
1939
                    $target_file,
0 ignored issues
show
Bug introduced by
It seems like $target_file defined by $antiXss->xss_clean($target_file) on line 1863 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...
1940
                    $password
1941
                );
1942
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1943
                $err = "wrong_key";
1944
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1945
                $err = $ex;
1946
            } catch (Defuse\Crypto\Exception\IOException $ex) {
1947
                $err = $ex;
1948
            }
1949
        }
1950
    }
1951
1952
    // return error
1953
    if (empty($err) === false) {
1954
        return $err;
1955
    } else {
1956
        return true;
1957
    }
1958
}
1959
1960
/*
1961
* NOT TO BE USED
1962
*/
1963
function debugTeampass($text)
1964
{
1965
    $debugFile = fopen('D:/wamp64/www/TeamPass/debug.txt', 'r+');
1966
    fputs($debugFile, $text);
1967
    fclose($debugFile);
1968
}
1969
1970
1971
/**
1972
 * DELETE the file with expected command depending on server type
1973
 * @param  string $file Path to file
1974
 * @return              Nothing
1975
 */
1976
function fileDelete($file)
1977
{
1978
    global $SETTINGS;
1979
1980
    // Load AntiXSS
1981
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXss.php';
1982
    $antiXss = new protect\AntiXSS\AntiXSS();
1983
1984
    $file = $antiXss->xss_clean($file);
1985
    if (is_file($file)) {
1986
        unlink($file);
0 ignored issues
show
Security File Manipulation introduced by
$file can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

6 paths for user data to reach this point

  1. Path: Read from $_POST, and $_POST['option'] is passed through filter_var(), and filter_var($_POST['option'], FILTER_SANITIZE_STRING) is passed through explode(), and $dataPost is assigned in sources/admin.queries.php on line 373
  1. Read from $_POST, and $_POST['option'] is passed through filter_var(), and filter_var($_POST['option'], FILTER_SANITIZE_STRING) is passed through explode(), and $dataPost is assigned
    in sources/admin.queries.php on line 373
  2. $dataPost[0] is escaped by htmlspecialchars() for html (no single-quotes) context(s), and $file is assigned
    in sources/admin.queries.php on line 374
  3. $SETTINGS['path_to_files_folder'] . '/' . $file is passed to fileDelete()
    in sources/admin.queries.php on line 393
  4. $file is assigned
    in sources/main.functions.php on line 1984
  2. Path: Read from $_POST, and (string) $_POST['list'] is passed through explode(), and $filesList is assigned in sources/admin.queries.php on line 1347
  1. Read from $_POST, and (string) $_POST['list'] is passed through explode(), and $filesList is assigned
    in sources/admin.queries.php on line 1347
  2. $file is assigned
    in sources/admin.queries.php on line 1348
  3. $SETTINGS['path_to_upload_folder'] . '/' . $file is passed to fileDelete()
    in sources/admin.queries.php on line 1368
  4. $file is assigned
    in sources/main.functions.php on line 1984
  3. Path: Read from $_POST, and $file is assigned in sources/import.queries.php on line 114
  1. Read from $_POST, and $file is assigned
    in sources/import.queries.php on line 114
  2. $file is passed to fileDelete()
    in sources/import.queries.php on line 203
  3. $file is assigned
    in sources/main.functions.php on line 1984
  4. Path: Read from $_POST, and $_POST['title'] is passed through substr(), and $extension is assigned in sources/items.queries.php on line 3372
  1. Read from $_POST, and $_POST['title'] is passed through substr(), and $extension is assigned
    in sources/items.queries.php on line 3372
  2. $SETTINGS['path_to_upload_folder'] . '/' . $image_code . '_delete.' . $extension is passed to fileDelete()
    in sources/items.queries.php on line 3382
  3. $file is assigned
    in sources/main.functions.php on line 1984
  5. Path: Read from $_POST, and $SETTINGS['path_to_upload_folder'] . '/' . $antiXss->xss_clean($result['file'] . $_POST['file_suffix']) is passed to fileDelete() in sources/items.queries.php on line 3425
  1. Read from $_POST, and $SETTINGS['path_to_upload_folder'] . '/' . $antiXss->xss_clean($result['file'] . $_POST['file_suffix']) is passed to fileDelete()
    in sources/items.queries.php on line 3425
  2. $file is assigned
    in sources/main.functions.php on line 1984
  6. Path: Read from $_POST, and $_POST['filename'] is passed to fileDelete() in sources/main.queries.php on line 1137
  1. Read from $_POST, and $_POST['filename'] is passed to fileDelete()
    in sources/main.queries.php on line 1137
  2. $file is assigned
    in sources/main.functions.php on line 1984

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...
1987
    }
1988
}
1989
1990
/*
1991
* Permits to extract the file extension
1992
*/
1993
function getFileExtension($f)
1994
{
1995
    if (strpos($f, '.') === false) {
1996
        return $f;
1997
    }
1998
1999
    return substr($f, strrpos($f, '.') + 1);
2000
}
2001
2002
/**
2003
 * array_map
2004
 * @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...
2005
 * @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...
2006
 * @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...
2007
 */
2008
function array_map_r($func, $arr)
2009
{
2010
    $newArr = array();
2011
2012
    foreach ($arr as $key => $value) {
2013
        $newArr[ $key ] = (is_array($value) ? array_map_r($func, $value) : ( is_array($func) ? call_user_func_array($func, $value) : $func( $value )));
2014
    }
2015
2016
    return $newArr;
2017
}
2018
2019
/**
2020
 * Permits to clean and sanitize text to be displayed
2021
 * @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...
2022
 * @param  string $type what clean to perform
2023
 * @return string       text cleaned up
2024
 */
2025
function cleanText($string, $type = "")
2026
{
2027
    global $SETTINGS;
2028
2029
    // Load AntiXSS
2030
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXss.php';
2031
    $antiXss = new protect\AntiXSS\AntiXSS();
2032
2033
    if ($type === "css") {
2034
        // Escape text and quotes in UTF8 format
2035
        return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2036
    } elseif ($type === "html" || empty($type)) {
2037
        // Html cleaner
2038
        return $antiXss->xss_clean($string);
2039
    }
2040
}
2041