Completed
Push — development ( c392ac...98d449 )
by Nils
08:13
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 phpCrypt
20
if (!isset($_SESSION['settings']['cpassman_dir']) || empty($_SESSION['settings']['cpassman_dir'])) {
21
    require_once '../includes/libraries/phpcrypt/phpCrypt.php';
22
    require_once '../includes/config/settings.php';
23 View Code Duplication
} else {
24
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/phpcrypt/phpCrypt.php';
25
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/config/settings.php';
26
}
27
28
// Prepare PHPCrypt class calls
29
use PHP_Crypt\PHP_Crypt as PHP_Crypt;
30
31
// Prepare Encryption class calls
32
use \Defuse\Crypto\Crypto;
33
use \Defuse\Crypto\Exception as Ex;
34
35
//Generate N# of random bits for use as salt
36
/**
37
 * @param integer $n
38
 */
39
function getBits($n)
40
{
41
    $str = '';
42
    $x = $n + 10;
43
    for ($i = 0; $i < $x; $i++) {
44
        $str .= base_convert(mt_rand(1, 36), 10, 36);
45
    }
46
    return substr($str, 0, $n);
47
}
48
49
//generate pbkdf2 compliant hash
50 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...
51
{
52
    $kb = $st + $kl; // Key blocks to compute
53
    $dk = ''; // Derived key
54
55
    for ($block = 1; $block <= $kb; $block++) { // Create key
56
        $ib = $h = hash_hmac($a, $s.pack('N', $block), $p, true); // Initial hash for this block
57
        for ($i = 1; $i < $c; $i++) { // Perform block iterations
58
            $ib ^= ($h = hash_hmac($a, $h, $p, true)); // XOR each iterate
59
        }
60
        $dk .= $ib; // Append iterated block
61
    }
62
    return substr($dk, $st, $kl); // Return derived key of correct length
63
}
64
65
/**
66
 * stringUtf8Decode()
67
 *
68
 * utf8_decode
69
 */
70
function stringUtf8Decode($string)
71
{
72
    return str_replace(" ", "+", utf8_decode($string));
73
}
74
75
/**
76
 * encryptOld()
77
 *
78
 * crypt a string
79
 * @param string $text
80
 */
81 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...
82
{
83
    if (!empty($personalSalt)) {
84
        return trim(
85
            base64_encode(
86
                mcrypt_encrypt(
87
                    MCRYPT_RIJNDAEL_256,
88
                    $personalSalt,
89
                    $text,
90
                    MCRYPT_MODE_ECB,
91
                    mcrypt_create_iv(
92
                        mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
93
                        MCRYPT_RAND
94
                    )
95
                )
96
            )
97
        );
98
    } else {
99
        return trim(
100
            base64_encode(
101
                mcrypt_encrypt(
102
                    MCRYPT_RIJNDAEL_256,
103
                    SALT,
104
                    $text,
105
                    MCRYPT_MODE_ECB,
106
                    mcrypt_create_iv(
107
                        mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
108
                        MCRYPT_RAND
109
                    )
110
                )
111
            )
112
        );
113
    }
114
}
115
116
/**
117
 * decryptOld()
118
 *
119
 * decrypt a crypted string
120
 */
121 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...
122
{
123
    if (!empty($personalSalt)) {
124
        return trim(
125
            mcrypt_decrypt(
126
                MCRYPT_RIJNDAEL_256,
127
                $personalSalt,
128
                base64_decode($text),
129
                MCRYPT_MODE_ECB,
130
                mcrypt_create_iv(
131
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
132
                    MCRYPT_RAND
133
                )
134
            )
135
        );
136
    } else {
137
        return trim(
138
            mcrypt_decrypt(
139
                MCRYPT_RIJNDAEL_256,
140
                SALT,
141
                base64_decode($text),
142
                MCRYPT_MODE_ECB,
143
                mcrypt_create_iv(
144
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
145
                    MCRYPT_RAND
146
                )
147
            )
148
        );
149
    }
150
}
151
152
/**
153
 * encrypt()
154
 *
155
 * crypt a string
156
 * @param string $decrypted
157
 */
158
function encrypt($decrypted, $personalSalt = "")
159
{
160 View Code Duplication
    if (!isset($_SESSION['settings']['cpassman_dir']) || empty($_SESSION['settings']['cpassman_dir'])) {
161
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
162
    } else {
163
        require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
164
    }
165
166
    if (!empty($personalSalt)) {
167
            $staticSalt = $personalSalt;
168
    } else {
169
            $staticSalt = SALT;
170
    }
171
172
    //set our salt to a variable
173
    // Get 64 random bits for the salt for pbkdf2
174
    $pbkdf2Salt = getBits(64);
175
    // generate a pbkdf2 key to use for the encryption.
176
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
177
    // Build $iv and $ivBase64.  We use a block size of 256 bits (AES compliant)
178
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
179
    $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);
180
181
    //base64 trim
182
    if (strlen($ivBase64 = rtrim(base64_encode($iv), '=')) != 43) {
183
        return false;
184
    }
185
    // Encrypt $decrypted
186
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $iv);
187
    // MAC the encrypted text
188
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
189
    // We're done!
190
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
191
}
192
193
/**
194
 * decrypt()
195
 *
196
 * decrypt a crypted string
197
 */
198
function decrypt($encrypted, $personalSalt = "")
199
{
200 View Code Duplication
    if (!isset($_SESSION['settings']['cpassman_dir']) || empty($_SESSION['settings']['cpassman_dir'])) {
201
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
202
    } else {
203
        require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
204
    }
205
206
    if (!empty($personalSalt)) {
207
        $staticSalt = $personalSalt;
208
    } else {
209
        $staticSalt = SALT;
210
    }
211
    //base64 decode the entire payload
212
    $encrypted = base64_decode($encrypted);
213
    // get the salt
214
    $pbkdf2Salt = substr($encrypted, -64);
215
    //remove the salt from the string
216
    $encrypted = substr($encrypted, 0, -64);
217
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
218
    // Retrieve $iv which is the first 22 characters plus ==, base64_decoded.
219
    $iv = base64_decode(substr($encrypted, 0, 43).'==');
220
    // Remove $iv from $encrypted.
221
    $encrypted = substr($encrypted, 43);
222
    // Retrieve $mac which is the last 64 characters of $encrypted.
223
    $mac = substr($encrypted, -64);
224
    // Remove the last 64 chars from encrypted (remove MAC)
225
    $encrypted = substr($encrypted, 0, -64);
226
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
227
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
228
        return false;
229
    }
230
    // Decrypt the data.
231
    $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $iv), "\0\4");
232
    // Yay!
233
    return $decrypted;
234
}
235
236
237
/**
238
 * genHash()
239
 *
240
 * Generate a hash for user login
241
 * @param string $password
242
 */
243
function bCrypt($password, $cost)
244
{
245
    $salt = sprintf('$2y$%02d$', $cost);
246
    if (function_exists('openssl_random_pseudo_bytes')) {
247
        $salt .= bin2hex(openssl_random_pseudo_bytes(11));
248
    } else {
249
        $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
250
        for ($i = 0; $i < 22; $i++) {
251
            $salt .= $chars[mt_rand(0, 63)];
252
        }
253
    }
254
    return crypt($password, $salt);
255
}
256
257
function cryption_before_defuse($message, $sk, $iv, $type = null, $scope = "public")
258
{
259
    if (DEFUSE_ENCRYPTION === true) {
260
        if ($scope === "perso") {
261
            return defuse_crypto(
262
                $message,
263
                $sk,
264
                $type
265
            );
266
        } else {
267
            return defuse_crypto(
268
                $message,
269
                file_get_contents(SECUREPATH."/teampass-seckey.txt"),
270
                $type
271
            );
272
        }
273
    } else {
274
        return cryption_phpCrypt($message, $sk, $iv, $type);
275
    }
276
}
277
278
/*
279
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
280
 *
281
 * Using AES_128 and mode CBC
282
 *
283
 * $key and $iv have to be given in hex format
284
 */
285
function cryption_phpCrypt($string, $key, $iv, $type)
286
{
287
    // manage key origin
288
    define('SALT', 'LEfzTjADMTzV6qHC');
289
290
    if ($key != SALT) {
291
        // check key (AES-128 requires a 16 bytes length key)
292
        if (strlen($key) < 16) {
293
            for ($x = strlen($key) + 1; $x <= 16; $x++) {
294
                $key .= chr(0);
295
            }
296
        } elseif (strlen($key) > 16) {
297
            $key = substr($key, 16);
298
        }
299
    }
300
301
    // load crypt
302
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
303
304
    if ($type == "encrypt") {
305
        // generate IV and encrypt
306
        $iv = $crypt->createIV();
307
        $encrypt = $crypt->encrypt($string);
308
        // return
309
        return array(
310
            "string" => bin2hex($encrypt),
311
            "iv" => bin2hex($iv),
312
            "error" => empty($encrypt) ? "ERR_ENCRYPTION_NOT_CORRECT" : ""
313
        );
314
    } elseif ($type == "decrypt") {
315
        // case if IV is empty
316
        if (empty($iv)) {
317
                    return array(
318
                'string' => "",
319
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
320
            );
321
        }
322
323
        // convert
324
        try {
325
            $string = testHex2Bin(trim($string));
326
            $iv = testHex2Bin($iv);
327
        } catch (Exception $e) {
328
            return array(
329
                'string' => "",
330
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
331
            );
332
        }
333
334
        // load IV
335
        $crypt->IV($iv);
336
        // decrypt
337
        $decrypt = $crypt->decrypt($string);
338
        // return
339
        return array(
340
            'string' => str_replace(chr(0), "", $decrypt),
341
            'error' => ""
342
        );
343
    }
344
}
345
346
function testHex2Bin($val)
347
{
348
    if (!@hex2bin($val)) {
349
        throw new Exception("ERROR");
350
    }
351
    return hex2bin($val);
352
}
353
354
/**
355
 * @param string $ascii_key
356
 * @param string $type
357
 */
358
function cryption($message, $ascii_key, $type) //defuse_crypto
359
{
360
    // load PhpEncryption library
361 View Code Duplication
    if (!isset($_SESSION['settings']['cpassman_dir']) || empty($_SESSION['settings']['cpassman_dir'])) {
362
        $path = '../includes/libraries/Encryption/Encryption/';
363
    } else {
364
        $path = $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
365
    }
366
367
    require_once $path.'Crypto.php';
368
    require_once $path.'Encoding.php';
369
    require_once $path.'DerivedKeys.php';
370
    require_once $path.'Key.php';
371
    require_once $path.'KeyOrPassword.php';
372
    require_once $path.'File.php';
373
    require_once $path.'RuntimeTests.php';
374
    require_once $path.'KeyProtectedByPassword.php';
375
    require_once $path.'Core.php';
376
377
    // init
378
    $err = '';
379
    if (empty($ascii_key)) {
380
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
381
    }
382
383
    // convert KEY
384
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
385
386
    try {
387
        if ($type === "encrypt") {
388
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
389
        } elseif ($type === "decrypt") {
390
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
391
        }
392
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
393
        $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.";
394
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
395
        $err = $ex;
396
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
397
        $err = $ex;
398
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
399
        $err = $ex;
400
    } catch (Defuse\Crypto\Exception\IOException $ex) {
401
        $err = $ex;
402
    }
403
404
    return array(
405
        'string' => isset($text) ? $text : "",
406
        'error' => $err
407
    );
408
}
409
410
function defuse_generate_key()
411
{
412
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
413
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
414
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
415
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
416
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
417
    require_once '../includes/libraries/Encryption/Encryption/File.php';
418
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
419
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
420
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
421
422
    $key = \Defuse\Crypto\Key::createNewRandomKey();
423
    $key = $key->saveToAsciiSafeString();
424
    return $key;
425
}
426
427
function defuse_generate_personal_key($psk)
428
{
429
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
430
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
431
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
432
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
433
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
434
    require_once '../includes/libraries/Encryption/Encryption/File.php';
435
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
436
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
437
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
438
439
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
440
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
441
442
    return $protected_key_encoded; // save this in user table
443
}
444
445
/**
446
 * @param string $psk
447
 */
448
function defuse_validate_personal_key($psk, $protected_key_encoded)
449
{
450
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
451
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
452
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
453
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
454
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
455
    require_once '../includes/libraries/Encryption/Encryption/File.php';
456
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
457
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
458
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
459
460
    try {
461
        $protected_key = \Defuse\Crypto\KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
462
        $user_key = $protected_key->unlockKey($psk);
463
        $user_key_encoded = $user_key->saveToAsciiSafeString();
464
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
465
        return "Error - Major issue as the encryption is broken.";
466
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
467
        return "Error - The saltkey is not the correct one.";
468
    }
469
470
    return $user_key_encoded; // store it in session once user has entered his psk
471
}
472
473
/**
474
 * trimElement()
475
 *
476
 * trim a string depending on a specific string
477
 * @param string $element
478
 * @return string
479
 */
480
function trimElement($chaine, $element)
481
{
482
    if (!empty($chaine)) {
483
        $chaine = trim($chaine);
484
        if (substr($chaine, 0, 1) == $element) {
485
            $chaine = substr($chaine, 1);
486
        }
487
        if (substr($chaine, strlen($chaine) - 1, 1) == $element) {
488
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
489
        }
490
    }
491
    return $chaine;
492
}
493
494
/**
495
 * cleanString()
496
 *
497
 * permits to suppress all "special" characters from string
498
 */
499
function cleanString($string, $special = false)
500
{
501
    // Create temporary table for special characters escape
502
    $tabSpecialChar = array();
503
    for ($i = 0; $i <= 31; $i++) {
504
        $tabSpecialChar[] = chr($i);
505
    }
506
    array_push($tabSpecialChar, "<br />");
507
    if ($special == "1") {
508
        $tabSpecialChar = array_merge($tabSpecialChar, array("</li>", "<ul>", "<ol>"));
509
    }
510
511
    return str_replace($tabSpecialChar, "\n", $string);
512
}
513
514
function db_error_handler($params)
515
{
516
    echo "Error: ".$params['error']."<br>\n";
517
    echo "Query: ".$params['query']."<br>\n";
518
    die; // don't want to keep going if a query broke
519
}
520
521
/**
522
 * identifyUserRights()
523
 *
524
 * @return
525
 * @param boolean $refresh
526
 */
527
function identifyUserRights($groupesVisiblesUser, $groupesInterditsUser, $isAdmin, $idFonctions, $refresh)
528
{
529
    global $server, $user, $pass, $database, $pre, $port, $encoding;
530
531
    //load ClassLoader
532
    require_once $_SESSION['settings']['cpassman_dir'].'/sources/SplClassLoader.php';
533
534
    //Connect to DB
535
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
536
    DB::$host = $server;
537
    DB::$user = $user;
538
    DB::$password = $pass;
539
    DB::$dbName = $database;
540
    DB::$port = $port;
541
    DB::$encoding = $encoding;
542
    DB::$error_handler = true;
543
    $link = mysqli_connect($server, $user, $pass, $database, $port);
544
    $link->set_charset($encoding);
545
546
    //Build tree
547
    $tree = new SplClassLoader('Tree\NestedTree', $_SESSION['settings']['cpassman_dir'].'/includes/libraries');
548
    $tree->register();
549
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
550
551
    // Check if user is ADMINISTRATOR
552
    if ($isAdmin == 1) {
553
        $groupesVisibles = array();
554
        $_SESSION['personal_folders'] = array();
555
        $_SESSION['groupes_visibles'] = array();
556
        $_SESSION['groupes_interdits'] = array();
557
        $_SESSION['personal_visible_groups'] = array();
558
        $_SESSION['read_only_folders'] = array();
559
        $_SESSION['list_restricted_folders_for_items'] = array();
560
        $_SESSION['list_folders_editable_by_role'] = array();
561
        $_SESSION['list_folders_limited'] = array();
562
        $_SESSION['groupes_visibles_list'] = "";
563
        $_SESSION['list_folders_limited'] = "";
564
        $rows = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i", 0);
565
        foreach ($rows as $record) {
566
            array_push($groupesVisibles, $record['id']);
567
        }
568
        $_SESSION['groupes_visibles'] = $groupesVisibles;
569
        $_SESSION['all_non_personal_folders'] = $groupesVisibles;
570
        // Exclude all PF
571
        $_SESSION['forbiden_pfs'] = array();
572
        $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
573
        $where->add('personal_folder=%i', 1);
574
        if (isset($_SESSION['settings']['enable_pf_feature']) && $_SESSION['settings']['enable_pf_feature'] == 1) {
575
            $where->add('title=%s', $_SESSION['user_id']);
576
            $where->negateLast();
577
        }
578
        // Get ID of personal folder
579
        $pf = DB::queryfirstrow(
580
            "SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s",
581
            $_SESSION['user_id']
582
        );
583
        if (!empty($pf['id'])) {
584
            if (!in_array($pf['id'], $_SESSION['groupes_visibles'])) {
585
                array_push($_SESSION['groupes_visibles'], $pf['id']);
586
                array_push($_SESSION['personal_visible_groups'], $pf['id']);
587
                // get all descendants
588
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
589
                $tree->rebuild();
590
                $tst = $tree->getDescendants($pf['id']);
591
                foreach ($tst as $t) {
592
                    array_push($_SESSION['groupes_visibles'], $t->id);
593
                    array_push($_SESSION['personal_visible_groups'], $t->id);
594
                }
595
            }
596
        }
597
598
        // get complete list of ROLES
599
        $tmp = explode(";", $_SESSION['fonction_id']);
600
        $rows = DB::query(
601
            "SELECT * FROM ".prefix_table("roles_title")."
602
            ORDER BY title ASC"
603
        );
604
        foreach ($rows as $record) {
605
            if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
606
                array_push($tmp, $record['id']);
607
            }
608
        }
609
        $_SESSION['fonction_id'] = implode(";", $tmp);
610
611
        $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
612
        $_SESSION['is_admin'] = $isAdmin;
613
        // Check if admin has created Folders and Roles
614
        DB::query("SELECT * FROM ".prefix_table("nested_tree")."");
615
        $_SESSION['nb_folders'] = DB::count();
616
        DB::query("SELECT * FROM ".prefix_table("roles_title"));
617
        $_SESSION['nb_roles'] = DB::count();
618
    } else {
619
        // init
620
        $_SESSION['groupes_visibles'] = array();
621
        $_SESSION['personal_folders'] = array();
622
        $_SESSION['groupes_interdits'] = array();
623
        $_SESSION['personal_visible_groups'] = array();
624
        $_SESSION['read_only_folders'] = array();
625
        $groupesInterdits = array();
626
        if (!is_array($groupesInterditsUser)) {
627
            $groupesInterditsUser = explode(';', trimElement($groupesInterditsUser, ";"));
628
        }
629
        if (!empty($groupesInterditsUser) && count($groupesInterditsUser) > 0) {
630
            $groupesInterdits = $groupesInterditsUser;
631
        }
632
        $_SESSION['is_admin'] = $isAdmin;
633
        $fonctionsAssociees = explode(';', trimElement($idFonctions, ";"));
634
635
        $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
636
637
        // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
638
        foreach ($fonctionsAssociees as $roleId) {
639
            if (!empty($roleId)) {
640
                // Get allowed folders for each Role
641
                $rows = DB::query("SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id=%i", $roleId);
642
643
                if (DB::count() > 0) {
644
                    $tmp = DB::queryfirstrow("SELECT allow_pw_change FROM ".prefix_table("roles_title")." WHERE id = %i", $roleId);
645
                    foreach ($rows as $record) {
646
                        if (isset($record['folder_id']) && !in_array($record['folder_id'], $listAllowedFolders)) {
647
                            array_push($listAllowedFolders, $record['folder_id']);
648
                        }
649
                        // Check if this group is allowed to modify any pw in allowed folders
650
                        if ($tmp['allow_pw_change'] == 1 && !in_array($record['folder_id'], $listFoldersEditableByRole)) {
651
                            array_push($listFoldersEditableByRole, $record['folder_id']);
652
                        }
653
                    }
654
                    // Check for the users roles if some specific rights exist on items
655
                    $rows = DB::query(
656
                        "SELECT i.id_tree, r.item_id
657
                        FROM ".prefix_table("items")." as i
658
                        INNER JOIN ".prefix_table("restriction_to_roles")." as r ON (r.item_id=i.id)
659
                        WHERE r.role_id=%i
660
                        ORDER BY i.id_tree ASC",
661
                        $roleId
662
                    );
663
                    $x = 0;
664
                    foreach ($rows as $record) {
665
                        if (isset($record['id_tree'])) {
666
                            $listFoldersLimited[$record['id_tree']][$x] = $record['item_id'];
667
                            $x++;
668
                        }
669
                    }
670
                }
671
            }
672
        }
673
674
        // Does this user is allowed to see other items
675
        $x = 0;
676
        $rows = DB::query(
677
            "SELECT id, id_tree FROM ".prefix_table("items")."
678
            WHERE restricted_to LIKE %ss AND inactif=%s",
679
            $_SESSION['user_id'].';',
680
            '0'
681
        );
682
        foreach ($rows as $record) {
683
            $listRestrictedFoldersForItems[$record['id_tree']][$x] = $record['id'];
684
            $x++;
685
        }
686
        // => Build final lists
687
        // Clean arrays
688
        $listAllowedFolders = array_unique($listAllowedFolders);
689
        $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ";"));
690
        // Add user allowed folders
691
        $allowedFoldersTmp = array_unique(
692
            array_merge($listAllowedFolders, $groupesVisiblesUser)
693
        );
694
        // Exclude from allowed folders all the specific user forbidden folders
695
        $allowedFolders = array();
696
        foreach ($allowedFoldersTmp as $id) {
697
            if (!in_array($id, $groupesInterditsUser) && !empty($id)) {
698
                array_push($allowedFolders, $id);
699
            }
700
        }
701
702
        // Clean array
703
        $listAllowedFolders = array_filter(array_unique($allowedFolders));
704
705
        // Exclude all PF
706
        $_SESSION['forbiden_pfs'] = array();
707
708
        $where = new WhereClause('and');
709
        $where->add('personal_folder=%i', 1);
710
        if (isset($_SESSION['settings']['enable_pf_feature']) &&
711
            $_SESSION['settings']['enable_pf_feature'] == 1 &&
712
            isset($_SESSION['personal_folder']) &&
713
            $_SESSION['personal_folder'] == 1
714
        ) {
715
            $where->add('title=%s', $_SESSION['user_id']);
716
            $where->negateLast();
717
        }
718
719
        $pfs = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE %l", $where);
720
        foreach ($pfs as $pfId) {
721
            array_push($_SESSION['forbiden_pfs'], $pfId['id']);
722
        }
723
        // Get IDs of personal folders
724
        if (isset($_SESSION['settings']['enable_pf_feature']) &&
725
            $_SESSION['settings']['enable_pf_feature'] == 1 &&
726
            isset($_SESSION['personal_folder']) &&
727
            $_SESSION['personal_folder'] == 1
728
        ) {
729
            $pf = DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s", $_SESSION['user_id']);
730
            if (!empty($pf['id'])) {
731
                if (!in_array($pf['id'], $listAllowedFolders)) {
732
                    array_push($_SESSION['personal_folders'], $pf['id']);
733
                    // get all descendants
734
                    $ids = $tree->getDescendants($pf['id'], true, false);
735
                    foreach ($ids as $id) {
736
                        array_push($listAllowedFolders, $id->id);
737
                        array_push($_SESSION['personal_visible_groups'], $id->id);
738
                        array_push($_SESSION['personal_folders'], $id->id);
739
                    }
740
                }
741
            }
742
            // get list of readonly folders when pf is disabled.
743
            // rule - if one folder is set as W or N in one of the Role, then User has access as W
744
            foreach ($listAllowedFolders as $folderId) {
745
                if (!in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders'])))) {   //
746
                    DB::query(
747
                        "SELECT *
748
                        FROM ".prefix_table("roles_values")."
749
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
750
                        $folderId,
751
                        $fonctionsAssociees,
752
                        array("W", "ND", "NE", "NDNE")
753
                    );
754
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
755
                        array_push($listReadOnlyFolders, $folderId);
756
                    }
757
                }
758
            }
759
        } else {
760
            // get list of readonly folders when pf is disabled.
761
            // rule - if one folder is set as W in one of the Role, then User has access as W
762
            foreach ($listAllowedFolders as $folderId) {
763
                if (!in_array($folderId, $listReadOnlyFolders)) {
764
                    DB::query(
765
                        "SELECT *
766
                        FROM ".prefix_table("roles_values")."
767
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
768
                        $folderId,
769
                        $fonctionsAssociees,
770
                        array("W", "ND", "NE", "NDNE")
771
                    );
772
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
773
                        array_push($listReadOnlyFolders, $folderId);
774
                    }
775
                }
776
            }
777
        }
778
779
        // check if change proposals on User's items
780
        if (isset($_SESSION['settings']['enable_suggestion']) && $_SESSION['settings']['enable_suggestion'] == 1) {
781
            DB::query(
782
                "SELECT *
783
                FROM ".prefix_table("items_change")." AS c
784
                LEFT JOIN ".prefix_table("log_items")." AS i ON (c.item_id = i.id_item)
785
                WHERE i.action = %s AND i.id_user = %i",
786
                "at_creation",
787
                $_SESSION['user_id']
788
            );
789
            $_SESSION['nb_item_change_proposals'] = DB::count();
790
        } else {
791
            $_SESSION['nb_item_change_proposals'] = 0;
792
        }
793
794
        $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
795
        $_SESSION['groupes_visibles'] = $listAllowedFolders;
796
        $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
797
        $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
798
        $_SESSION['read_only_folders'] = $listReadOnlyFolders;
799
        $_SESSION['no_access_folders'] = $groupesInterdits;
800
801
        $_SESSION['list_folders_limited'] = $listFoldersLimited;
802
        $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
803
        $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
804
        // Folders and Roles numbers
805
        DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")."");
806
        $_SESSION['nb_folders'] = DB::count();
807
        DB::queryfirstrow("SELECT id FROM ".prefix_table("roles_title"));
808
        $_SESSION['nb_roles'] = DB::count();
809
    }
810
811
    // update user's timestamp
812
    DB::update(
813
        prefix_table('users'),
814
        array(
815
            'timestamp' => time()
816
        ),
817
        "id=%i",
818
        $_SESSION['user_id']
819
    );
820
}
821
822
/**
823
 * updateCacheTable()
824
 *
825
 * Update the CACHE table
826
 * @param string $action
827
 */
828
function updateCacheTable($action, $id = "")
829
{
830
    global $db, $server, $user, $pass, $database, $pre, $port, $encoding;
831
    require_once $_SESSION['settings']['cpassman_dir'].'/sources/SplClassLoader.php';
832
833
    //Connect to DB
834
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
835
    DB::$host = $server;
836
    DB::$user = $user;
837
    DB::$password = $pass;
838
    DB::$dbName = $database;
839
    DB::$port = $port;
840
    DB::$encoding = $encoding;
841
    DB::$error_handler = true;
842
    $link = mysqli_connect($server, $user, $pass, $database, $port);
843
    $link->set_charset($encoding);
844
845
    //Load Tree
846
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
847
    $tree->register();
848
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
849
850
    // Rebuild full cache table
851
    if ($action === "reload") {
852
        // truncate table
853
        DB::query("TRUNCATE TABLE ".$pre."cache");
854
855
        // reload date
856
        $rows = DB::query(
857
            "SELECT *
858
            FROM ".$pre."items as i
859
            INNER JOIN ".$pre."log_items as l ON (l.id_item = i.id)
860
            AND l.action = %s
861
            AND i.inactif = %i",
862
            'at_creation',
863
            0
864
        );
865
        foreach ($rows as $record) {
866
            // Get all TAGS
867
            $tags = "";
868
            $itemTags = DB::query("SELECT tag FROM ".$pre."tags WHERE item_id=%i", $record['id']);
869
            foreach ($itemTags as $itemTag) {
870
                if (!empty($itemTag['tag'])) {
871
                    $tags .= $itemTag['tag']." ";
872
                }
873
            }
874
            // Get renewal period
875
            $resNT = DB::queryfirstrow("SELECT renewal_period FROM ".$pre."nested_tree WHERE id=%i", $record['id_tree']);
876
877
            // form id_tree to full foldername
878
            $folder = "";
879
            $arbo = $tree->getPath($record['id_tree'], true);
880 View Code Duplication
            foreach ($arbo as $elem) {
881
                if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
882
                    $elem->title = $_SESSION['login'];
883
                }
884
                if (empty($folder)) {
885
                    $folder = stripslashes($elem->title);
886
                } else {
887
                    $folder .= " » ".stripslashes($elem->title);
888
                }
889
            }
890
            // store data
891
            DB::insert(
892
                $pre."cache",
893
                array(
894
                    'id' => $record['id'],
895
                    'label' => $record['label'],
896
                    'description' => isset($record['description']) ? $record['description'] : "",
897
                    'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : "0",
898
                    'tags' => $tags,
899
                    'id_tree' => $record['id_tree'],
900
                    'perso' => $record['perso'],
901
                    'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : "0",
902
                    'login' => isset($record['login']) ? $record['login'] : "",
903
                    'folder' => $folder,
904
                    'author' => $record['id_user'],
905
                    'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : "0",
906
                    'timestamp' => $record['date']
907
                    )
908
            );
909
        }
910
        // UPDATE an item
911
    } elseif ($action === "update_value") {
912
        // get new value from db
913
        $data = DB::queryfirstrow(
914
            "SELECT label, description, id_tree, perso, restricted_to, login, url
915
            FROM ".$pre."items
916
            WHERE id=%i",
917
            $id
918
        );
919
        // Get all TAGS
920
        $tags = "";
921
        $itemTags = DB::query("SELECT tag FROM ".$pre."tags WHERE item_id=%i", $id);
922
        foreach ($itemTags as $itemTag) {
923
            if (!empty($itemTag['tag'])) {
924
                $tags .= $itemTag['tag']." ";
925
            }
926
        }
927
        // form id_tree to full foldername
928
        $folder = "";
929
        $arbo = $tree->getPath($data['id_tree'], true);
930 View Code Duplication
        foreach ($arbo as $elem) {
931
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
932
                $elem->title = $_SESSION['login'];
933
            }
934
            if (empty($folder)) {
935
                $folder = stripslashes($elem->title);
936
            } else {
937
                $folder .= " » ".stripslashes($elem->title);
938
            }
939
        }
940
        // finaly update
941
        DB::update(
942
            $pre."cache",
943
            array(
944
                'label' => $data['label'],
945
                'description' => $data['description'],
946
                'tags' => $tags,
947
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
948
                'id_tree' => $data['id_tree'],
949
                'perso' => $data['perso'],
950
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
951
                'login' => isset($data['login']) ? $data['login'] : "",
952
                'folder' => $folder,
953
                'author' => $_SESSION['user_id'],
954
                ),
955
            "id = %i",
956
            $id
957
        );
958
        // ADD an item
959
    } elseif ($action === "add_value") {
960
        // get new value from db
961
        $data = DB::queryFirstRow(
962
            "SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
963
            FROM ".$pre."items as i
964
            INNER JOIN ".$pre."log_items as l ON (l.id_item = i.id)
965
            WHERE i.id = %i
966
            AND l.action = %s",
967
            $id,
968
            'at_creation'
969
        );
970
        // Get all TAGS
971
        $tags = "";
972
        $itemTags = DB::query("SELECT tag FROM ".$pre."tags WHERE item_id = %i", $id);
973
        foreach ($itemTags as $itemTag) {
974
            if (!empty($itemTag['tag'])) {
975
                $tags .= $itemTag['tag']." ";
976
            }
977
        }
978
        // form id_tree to full foldername
979
        $folder = "";
980
        $arbo = $tree->getPath($data['id_tree'], true);
981 View Code Duplication
        foreach ($arbo as $elem) {
982
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
983
                $elem->title = $_SESSION['login'];
984
            }
985
            if (empty($folder)) {
986
                $folder = stripslashes($elem->title);
987
            } else {
988
                $folder .= " » ".stripslashes($elem->title);
989
            }
990
        }
991
        // finaly update
992
        DB::insert(
993
            prefix_table("cache"),
994
            array(
995
                'id' => $data['id'],
996
                'label' => $data['label'],
997
                'description' => $data['description'],
998
                'tags' => (isset($tags) && !empty($tags)) ? $tags : "None",
999
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1000
                'id_tree' => $data['id_tree'],
1001
                'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== "None") ? $data['perso'] : "0",
1002
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "None",
1003
                'login' => isset($data['login']) ? $data['login'] : "",
1004
                'folder' => $folder,
1005
                'author' => $_SESSION['user_id'],
1006
                'timestamp' => $data['date']
1007
            )
1008
        );
1009
1010
        // DELETE an item
1011
    } elseif ($action === "delete_value") {
1012
        DB::delete($pre."cache", "id = %i", $id);
1013
    }
1014
}
1015
1016
/*
1017
*
1018
*/
1019
function getStatisticsData()
1020
{
1021
    DB::query(
1022
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1023
        0
1024
    );
1025
    $counter_folders = DB::count();
1026
1027
    DB::query(
1028
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1029
        1
1030
    );
1031
    $counter_folders_perso = DB::count();
1032
1033
    DB::query(
1034
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1035
        0
1036
    );
1037
    $counter_items = DB::count();
1038
1039
    DB::query(
1040
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1041
        1
1042
    );
1043
    $counter_items_perso = DB::count();
1044
1045
    DB::query(
1046
        "SELECT id FROM ".prefix_table("users").""
1047
    );
1048
    $counter_users = DB::count();
1049
1050
    DB::query(
1051
        "SELECT id FROM ".prefix_table("users")." WHERE admin = %i",
1052
        1
1053
    );
1054
    $admins = DB::count();
1055
1056
    DB::query(
1057
        "SELECT id FROM ".prefix_table("users")." WHERE gestionnaire = %i",
1058
        1
1059
    );
1060
    $managers = DB::count();
1061
1062
    DB::query(
1063
        "SELECT id FROM ".prefix_table("users")." WHERE read_only = %i",
1064
        1
1065
    );
1066
    $ro = DB::count();
1067
1068
    // list the languages
1069
    $usedLang = [];
1070
    $tp_languages = DB::query(
1071
        "SELECT name FROM ".prefix_table("languages")
1072
    );
1073
    foreach ($tp_languages as $tp_language) {
1074
        DB::query(
1075
            "SELECT * FROM ".prefix_table("users")." WHERE user_language = %s",
1076
            $tp_language['name']
1077
        );
1078
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1079
    }
1080
1081
    // get list of ips
1082
    $usedIp = [];
1083
    $tp_ips = DB::query(
1084
        "SELECT user_ip FROM ".prefix_table("users")
1085
    );
1086
    foreach ($tp_ips as $ip) {
1087
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1088
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1089
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== "none") {
1090
            $usedIp[$ip['user_ip']] = 1;
1091
        }
1092
    }
1093
1094
    return array(
1095
        "error" => "",
1096
        "stat_phpversion" => phpversion(),
1097
        "stat_folders" => $counter_folders,
1098
        "stat_folders_shared" => intval($counter_folders) - intval($counter_folders_perso),
1099
        "stat_items" => $counter_items,
1100
        "stat_items_shared" => intval($counter_items) - intval($counter_items_perso),
1101
        "stat_users" => $counter_users,
1102
        "stat_admins" => $admins,
1103
        "stat_managers" => $managers,
1104
        "stat_ro" => $ro,
1105
        "stat_kb" => $_SESSION['settings']['enable_kb'],
1106
        "stat_pf" => $_SESSION['settings']['enable_pf_feature'],
1107
        "stat_fav" => $_SESSION['settings']['enable_favourites'],
1108
        "stat_teampassversion" => $_SESSION['settings']['cpassman_version'],
1109
        "stat_ldap" => $_SESSION['settings']['ldap_mode'],
1110
        "stat_agses" => $_SESSION['settings']['agses_authentication_enabled'],
1111
        "stat_duo" => $_SESSION['settings']['duo'],
1112
        "stat_suggestion" => $_SESSION['settings']['enable_suggestion'],
1113
        "stat_api" => $_SESSION['settings']['api'],
1114
        "stat_customfields" => $_SESSION['settings']['item_extra_fields'],
1115
        "stat_syslog" => $_SESSION['settings']['syslog_enable'],
1116
        "stat_2fa" => $_SESSION['settings']['google_authentication'],
1117
        "stat_stricthttps" => $_SESSION['settings']['enable_sts'],
1118
        "stat_mysqlversion" => DB::serverVersion(),
1119
        "stat_languages" => $usedLang,
1120
        "stat_country" => $usedIp
1121
    );
1122
}
1123
1124
/**
1125
 * sendEmail()
1126
 *
1127
 * @return
1128
 */
1129
function sendEmail($subject, $textMail, $email, $textMailAlt = "")
1130
{
1131
    global $LANG;
1132
    include $_SESSION['settings']['cpassman_dir'].'/includes/config/settings.php';
1133
    //load library
1134
    $user_language = isset($_SESSION['user_language']) ? $_SESSION['user_language'] : "english";
1135
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1136
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Email/Phpmailer/PHPMailerAutoload.php';
1137
1138
    // load PHPMailer
1139
    $mail = new PHPMailer();
1140
1141
    // send to user
1142
    $mail->setLanguage("en", "../includes/libraries/Email/Phpmailer/language/");
1143
    $mail->SMTPDebug = 0; //value 1 can be used to debug
1144
    $mail->Port = $_SESSION['settings']['email_port']; //COULD BE USED
1145
    $mail->CharSet = "utf-8";
1146
    $smtp_security = $_SESSION['settings']['email_security'];
1147
    if ($smtp_security == "tls" || $smtp_security == "ssl") {
1148
        $mail->SMTPSecure = $smtp_security;
1149
    }
1150
    $mail->isSmtp(); // send via SMTP
1151
    $mail->Host = $_SESSION['settings']['email_smtp_server']; // SMTP servers
1152
    $mail->SMTPAuth = $_SESSION['settings']['email_smtp_auth'] == '1' ? true : false; // turn on SMTP authentication
1153
    $mail->Username = $_SESSION['settings']['email_auth_username']; // SMTP username
1154
    $mail->Password = $_SESSION['settings']['email_auth_pwd']; // SMTP password
1155
    $mail->From = $_SESSION['settings']['email_from'];
1156
    $mail->FromName = $_SESSION['settings']['email_from_name'];
1157
    $mail->addAddress($email); //Destinataire
1158
    $mail->WordWrap = 80; // set word wrap
1159
    $mail->isHtml(true); // send as HTML
1160
    $mail->Subject = $subject;
1161
    $mail->Body = $textMail;
1162
    $mail->AltBody = $textMailAlt;
1163
    // send email
1164
    if (!$mail->send()) {
1165
        return '"error":"error_mail_not_send" , "message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1166
    } else {
1167
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1168
    }
1169
}
1170
1171
/**
1172
 * generateKey()
1173
 *
1174
 * @return
1175
 */
1176
function generateKey()
1177
{
1178
    return substr(md5(rand().rand()), 0, 15);
1179
}
1180
1181
/**
1182
 * dateToStamp()
1183
 *
1184
 * @return
1185
 */
1186
function dateToStamp($date)
1187
{
1188
    $date = date_parse_from_format($_SESSION['settings']['date_format'], $date);
1189
    if ($date['warning_count'] == 0 && $date['error_count'] == 0) {
1190
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1191
    } else {
1192
        return false;
1193
    }
1194
}
1195
1196
function isDate($date)
1197
{
1198
    return (strtotime($date) !== false);
1199
}
1200
1201
/**
1202
 * isUTF8()
1203
 *
1204
 * @return integer is the string in UTF8 format.
1205
 */
1206
1207
function isUTF8($string)
1208
{
1209
    if (is_array($string) === true) {
1210
        $string = $string['string'];
1211
    }
1212
    return preg_match(
1213
        '%^(?:
1214
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1215
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1216
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1217
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1218
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1219
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1220
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1221
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1222
        )*$%xs',
1223
        $string
1224
    );
1225
}
1226
1227
/*
1228
* FUNCTION
1229
* permits to prepare data to be exchanged
1230
*/
1231
/**
1232
 * @param string $type
1233
 */
1234
function prepareExchangedData($data, $type)
1235
{
1236
    //load ClassLoader
1237
    require_once $_SESSION['settings']['cpassman_dir'].'/sources/SplClassLoader.php';
1238
    //Load AES
1239
    $aes = new SplClassLoader('Encryption\Crypt', '../includes/libraries');
1240
    $aes->register();
1241
1242
    if ($type == "encode") {
1243
        if (isset($_SESSION['settings']['encryptClientServer'])
1244
            && $_SESSION['settings']['encryptClientServer'] == 0
1245
        ) {
1246
            return json_encode(
1247
                $data,
1248
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1249
            );
1250
        } else {
1251
            return Encryption\Crypt\aesctr::encrypt(
1252
                json_encode(
1253
                    $data,
1254
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1255
                ),
1256
                $_SESSION['key'],
1257
                256
1258
            );
1259
        }
1260
    } elseif ($type == "decode") {
1261
        if (isset($_SESSION['settings']['encryptClientServer'])
1262
            && $_SESSION['settings']['encryptClientServer'] == 0
1263
        ) {
1264
            return json_decode(
1265
                $data,
1266
                true
1267
            );
1268
        } else {
1269
            return json_decode(
1270
                Encryption\Crypt\aesctr::decrypt(
1271
                    $data,
1272
                    $_SESSION['key'],
1273
                    256
1274
                ),
1275
                true
1276
            );
1277
        }
1278
    }
1279
}
1280
1281
function make_thumb($src, $dest, $desired_width)
1282
{
1283
    /* read the source image */
1284
    $source_image = imagecreatefrompng($src);
1285
    $width = imagesx($source_image);
1286
    $height = imagesy($source_image);
1287
1288
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1289
    $desired_height = floor($height * ($desired_width / $width));
1290
1291
    /* create a new, "virtual" image */
1292
    $virtual_image = imagecreatetruecolor($desired_width, $desired_height);
1293
1294
    /* copy source image at a resized size */
1295
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
1296
1297
    /* create the physical thumbnail image to its destination */
1298
    imagejpeg($virtual_image, $dest);
1299
}
1300
1301
/*
1302
** check table prefix in SQL query
1303
*/
1304
/**
1305
 * @param string $table
1306
 */
1307
function prefix_table($table)
1308
{
1309
    global $pre;
1310
    $safeTable = htmlspecialchars($pre.$table);
1311
    if (!empty($safeTable)) {
1312
        // sanitize string
1313
        return $safeTable;
1314
    } else {
1315
        // stop error no table
1316
        return "table_not_exists";
1317
    }
1318
}
1319
1320
/*
1321
 * Creates a KEY using PasswordLib
1322
 */
1323
function GenerateCryptKey($size = "", $secure = false, $numerals = false, $capitalize = false, $ambiguous = false, $symbols = false)
1324
{
1325
    // load library
1326
    $pwgen = new SplClassLoader('Encryption\PwGen', '../includes/libraries');
1327
    $pwgen->register();
1328
    $pwgen = new Encryption\PwGen\pwgen();
1329
1330
    // init
1331
    if (!empty($size)) {
1332
        $pwgen->setLength($size);
1333
    }
1334
    if (!empty($secure)) {
1335
        $pwgen->setSecure($secure);
1336
    }
1337
    if (!empty($numerals)) {
1338
        $pwgen->setNumerals($numerals);
1339
    }
1340
    if (!empty($capitalize)) {
1341
        $pwgen->setCapitalize($capitalize);
1342
    }
1343
    if (!empty($ambiguous)) {
1344
        $pwgen->setAmbiguous($ambiguous);
1345
    }
1346
    if (!empty($symbols)) {
1347
        $pwgen->setSymbols($symbols);
1348
    }
1349
1350
    // generate and send back
1351
    return $pwgen->generate();
1352
}
1353
1354
/*
1355
* Send sysLOG message
1356
* @param string $message
1357
* @param string $host
1358
*/
1359
function send_syslog($message, $host, $port, $component = "teampass")
1360
{
1361
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1362
        //$syslog_message = "<123>" . date('M d H:i:s ') . " " .$host . " " . $component . ": " . $message;
1363
    $syslog_message = "<123>".date('M d H:i:s ').$component.": ".$message;
1364
        socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1365
    socket_close($sock);
1366
}
1367
1368
1369
1370
/**
1371
 * logEvents()
1372
 *
1373
 * permits to log events into DB
1374
 * @param string $type
1375
 * @param string $label
1376
 * @param string $field_1
1377
 */
1378
function logEvents($type, $label, $who, $login = "", $field_1 = null)
1379
{
1380
    global $server, $user, $pass, $database, $pre, $port, $encoding;
1381
1382
    if (empty($who)) {
1383
        $who = get_client_ip_server();
1384
    }
1385
1386
    // include librairies & connect to DB
1387
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1388
    DB::$host = $server;
1389
    DB::$user = $user;
1390
    DB::$password = $pass;
1391
    DB::$dbName = $database;
1392
    DB::$port = $port;
1393
    DB::$encoding = $encoding;
1394
    DB::$error_handler = true;
1395
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1396
    $link->set_charset($encoding);
1397
1398
    DB::insert(
1399
        prefix_table("log_system"),
1400
        array(
1401
            'type' => $type,
1402
            'date' => time(),
1403
            'label' => $label,
1404
            'qui' => $who,
1405
            'field_1' => $field_1 === null ? "" : $field_1
1406
        )
1407
    );
1408
    if (isset($_SESSION['settings']['syslog_enable']) && $_SESSION['settings']['syslog_enable'] == 1) {
1409
        if ($type == "user_mngt") {
1410
            send_syslog(
1411
                "The User ".$login." perform the acction off ".$label." to the user ".$field_1." - ".$type,
1412
                $_SESSION['settings']['syslog_host'],
1413
                $_SESSION['settings']['syslog_port'],
1414
                "teampass"
1415
            );
1416
        } else {
1417
            send_syslog(
1418
                "The User ".$login." perform the acction off ".$label." - ".$type,
1419
                $_SESSION['settings']['syslog_host'],
1420
                $_SESSION['settings']['syslog_port'],
1421
                "teampass"
1422
            );
1423
        }
1424
    }
1425
}
1426
1427
/**
1428
 * @param string $item
1429
 * @param string $action
1430
 */
1431
function logItems($id, $item, $id_user, $action, $login = "", $raison = null, $raison_iv = null, $encryption_type = "")
1432
{
1433
    global $server, $user, $pass, $database, $pre, $port, $encoding;
1434
    // include librairies & connect to DB
1435
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1436
    DB::$host = $server;
1437
    DB::$user = $user;
1438
    DB::$password = $pass;
1439
    DB::$dbName = $database;
1440
    DB::$port = $port;
1441
    DB::$encoding = $encoding;
1442
    DB::$error_handler = true;
1443
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1444
    $link->set_charset($encoding);
1445
    DB::insert(
1446
        prefix_table("log_items"),
1447
        array(
1448
            'id_item' => $id,
1449
            'date' => time(),
1450
            'id_user' => $id_user,
1451
            'action' => $action,
1452
            'raison' => $raison,
1453
            'raison_iv' => $raison_iv,
1454
            'encryption_type' => $encryption_type
1455
        )
1456
    );
1457
    if (isset($_SESSION['settings']['syslog_enable']) && $_SESSION['settings']['syslog_enable'] == 1) {
1458
        send_syslog(
1459
            "The Item ".$item." was ".$action." by ".$login." ".$raison,
1460
            $_SESSION['settings']['syslog_host'],
1461
            $_SESSION['settings']['syslog_port'],
1462
            "teampass"
1463
        );
1464
    }
1465
}
1466
1467
/*
1468
* Function to get the client ip address
1469
 */
1470
function get_client_ip_server()
1471
{
1472
    if (getenv('HTTP_CLIENT_IP')) {
1473
            $ipaddress = getenv('HTTP_CLIENT_IP');
1474
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1475
            $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1476
    } elseif (getenv('HTTP_X_FORWARDED')) {
1477
            $ipaddress = getenv('HTTP_X_FORWARDED');
1478
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1479
            $ipaddress = getenv('HTTP_FORWARDED_FOR');
1480
    } elseif (getenv('HTTP_FORWARDED')) {
1481
            $ipaddress = getenv('HTTP_FORWARDED');
1482
    } elseif (getenv('REMOTE_ADDR')) {
1483
            $ipaddress = getenv('REMOTE_ADDR');
1484
    } else {
1485
            $ipaddress = 'UNKNOWN';
1486
    }
1487
1488
    return $ipaddress;
1489
}
1490
1491
/**
1492
 * Escape all HTML, JavaScript, and CSS
1493
 *
1494
 * @param string $input The input string
1495
 * @param string $encoding Which character encoding are we using?
1496
 * @return string
1497
 */
1498
function noHTML($input, $encoding = 'UTF-8')
1499
{
1500
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1501
}
1502
1503
/**
1504
 * handleConfigFile()
1505
 *
1506
 * permits to handle the Teampass config file
1507
 * $action accepts "rebuild" and "update"
1508
 */
1509
function handleConfigFile($action, $field = null, $value = null)
1510
{
1511
    global $server, $user, $pass, $database, $pre, $port, $encoding;
1512
    $tp_config_file = "../includes/config/tp.config.php";
1513
1514
    // Load AntiXSS
1515
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXss.php';
1516
    $antiXss = new protect\AntiXSS\AntiXSS();
1517
1518
    // include librairies & connect to DB
1519
    require_once $_SESSION['settings']['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1520
    DB::$host = $server;
1521
    DB::$user = $user;
1522
    DB::$password = $pass;
1523
    DB::$dbName = $database;
1524
    DB::$port = $port;
1525
    DB::$encoding = $encoding;
1526
    DB::$error_handler = true;
1527
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1528
    $link->set_charset($encoding);
1529
1530
    if (!file_exists($tp_config_file) || $action == "rebuild") {
1531
        // perform a copy
1532
        if (file_exists($tp_config_file)) {
1533
            if (!copy($tp_config_file, $tp_config_file.'.'.date("Y_m_d_His", time()))) {
1534
                return "ERROR: Could not copy file '".$tp_config_file."'";
1535
            }
1536
        }
1537
1538
        // regenerate
1539
        $data = array();
1540
        $data[0] = "<?php\n";
1541
        $data[1] = "global \$SETTINGS;\n";
1542
        $data[2] = "\$SETTINGS = array (\n";
1543
        $rows = DB::query(
1544
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s",
1545
            "admin"
1546
        );
1547
        foreach ($rows as $record) {
1548
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
1549
        }
1550
        array_push($data, ");");
1551
        $data = array_unique($data);
1552
    } elseif ($action == "update" && !empty($field)) {
1553
        $data = file($tp_config_file);
1554
        $x = 0;
1555
        $bFound = false;
1556
        foreach ($data as $line) {
1557
            if (stristr($line, ");")) {
1558
                break;
1559
            }
1560
1561
            //
1562
            if (stristr($line, "'".$field."' => '")) {
1563
                $data[$x] = "    '".$field."' => '".$antiXss->xss_clean($value)."',\n";
1564
                $bFound = true;
1565
                break;
1566
            }
1567
            $x++;
1568
        }
1569
        if ($bFound === false) {
1570
            $data[($x - 1)] = "    '".$field."' => '".$antiXss->xss_clean($value)."',\n";
1571
        }
1572
    }
1573
1574
    // update file
1575
    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 1754
  2. Data is decoded by json_decode()
    in vendor/sources/main.functions.php on line 1265
  3. $dataReceived is assigned
    in sources/admin.queries.php on line 1754
  4. $dataReceived['field'] is passed to handleConfigFile()
    in sources/admin.queries.php on line 1855
  5. $data is assigned
    in sources/main.functions.php on line 1570
  6. isset($data) ? $data : array() is passed through implode()
    in sources/main.functions.php on line 1575

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

5 paths for user data to reach this point

  1. Path: Read from $_POST, and $_POST['option'] is passed through explode(), and $dataPost is assigned in sources/admin.queries.php on line 358
  1. Read from $_POST, and $_POST['option'] is passed through explode(), and $dataPost is assigned
    in sources/admin.queries.php on line 358
  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 359
  3. $file is assigned
    in sources/admin.queries.php on line 379
  4. $file is passed to fileDelete()
    in sources/admin.queries.php on line 399
  5. $file is assigned
    in sources/main.functions.php on line 1933
  2. Path: Read from $_POST, and $file is assigned in sources/import.queries.php on line 105
  1. Read from $_POST, and $file is assigned
    in sources/import.queries.php on line 105
  2. $file is passed to fileDelete()
    in sources/import.queries.php on line 198
  3. $file is assigned
    in sources/main.functions.php on line 1933
  3. Path: Read from $_POST, and $_POST['title'] is passed through substr(), and $extension is assigned in sources/items.queries.php on line 3366
  1. Read from $_POST, and $_POST['title'] is passed through substr(), and $extension is assigned
    in sources/items.queries.php on line 3366
  2. $_SESSION['settings']['path_to_upload_folder'] . '/' . $image_code . '_delete.' . $extension is passed to fileDelete()
    in sources/items.queries.php on line 3376
  3. $file is assigned
    in sources/main.functions.php on line 1933
  4. Path: Read from $_POST, and $_SESSION['settings']['path_to_upload_folder'] . '/' . $antiXss->xss_clean($result['file'] . $_POST['file_suffix']) is passed to fileDelete() in sources/items.queries.php on line 3419
  1. Read from $_POST, and $_SESSION['settings']['path_to_upload_folder'] . '/' . $antiXss->xss_clean($result['file'] . $_POST['file_suffix']) is passed to fileDelete()
    in sources/items.queries.php on line 3419
  2. $file is assigned
    in sources/main.functions.php on line 1933
  5. Path: Read from $_POST, and $_POST['filename'] is passed to fileDelete() in sources/main.queries.php on line 1126
  1. Read from $_POST, and $_POST['filename'] is passed to fileDelete()
    in sources/main.queries.php on line 1126
  2. $file is assigned
    in sources/main.functions.php on line 1933

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...
1936
    }
1937
}
1938
1939
/*
1940
* Permits to extract the file extension
1941
*/
1942
function getFileExtension($f)
1943
{
1944
    if (strpos($f, '.') === false) {
1945
        return $f;
1946
    }
1947
1948
    return substr($f, strrpos($f, '.') + 1);
1949
}
1950
1951
/**
1952
 * @param  [type]
1953
 * @param  [type]
1954
 * @return [type]
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...
1955
 */
1956
function array_map_r($func, $arr)
1957
{
1958
    $newArr = array();
1959
1960
    foreach ($arr as $key => $value) {
1961
        $newArr[ $key ] = (is_array($value) ? array_map_r($func, $value) : ( is_array($func) ? call_user_func_array($func, $value) : $func( $value )));
1962
    }
1963
1964
    return $newArr;
1965
}
1966