Passed
Push — development ( 3324d9...24d0a9 )
by Nils
05:00
created

cryption_before_defuse()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 13
nc 3
nop 5
dl 0
loc 18
rs 9.4285
c 0
b 0
f 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 13 and the first side effect is on line 16.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

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

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

99
                /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
100
                    MCRYPT_RIJNDAEL_256,
101
                    $personalSalt,
102
                    $text,
103
                    MCRYPT_MODE_ECB,
104
                    mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

104
                    /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
105
                        mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

105
                        /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
106
                        MCRYPT_RAND
107
                    )
108
                )
109
            )
110
        );
111
    }
112
113
    // If $personalSalt is not empty
114
    return trim(
115
        base64_encode(
116
            mcrypt_encrypt(
1 ignored issue
show
Deprecated Code introduced by
The function mcrypt_encrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

116
            /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
117
                MCRYPT_RIJNDAEL_256,
118
                SALT,
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
119
                $text,
120
                MCRYPT_MODE_ECB,
121
                mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

121
                /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
122
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

122
                    /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
123
                    MCRYPT_RAND
124
                )
125
            )
126
        )
127
    );
128
}
129
130
/**
131
 * decryptOld()
132
 *
133
 * decrypt a crypted string
134
 */
135
function decryptOld($text, $personalSalt = "")
136
{
137
    if (!empty($personalSalt)) {
138
        return trim(
139
            mcrypt_decrypt(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

139
            /** @scrutinizer ignore-deprecated */ mcrypt_decrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
140
                MCRYPT_RIJNDAEL_256,
141
                $personalSalt,
142
                base64_decode($text),
143
                MCRYPT_MODE_ECB,
144
                mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

144
                /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
145
                    mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

145
                    /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
146
                    MCRYPT_RAND
147
                )
148
            )
149
        );
150
    }
151
152
    // No personal SK
153
    return trim(
154
        mcrypt_decrypt(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

154
        /** @scrutinizer ignore-deprecated */ mcrypt_decrypt(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
155
            MCRYPT_RIJNDAEL_256,
156
            SALT,
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
157
            base64_decode($text),
158
            MCRYPT_MODE_ECB,
159
            mcrypt_create_iv(
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

159
            /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
160
                mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

160
                /** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, MCRYPT_MODE_ECB),

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
161
                MCRYPT_RAND
162
            )
163
        )
164
    );
165
}
166
167
/**
168
 * encrypt()
169
 *
170
 * crypt a string
171
 * @param string $decrypted
172
 */
173
function encrypt($decrypted, $personalSalt = "")
174
{
175
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
176
177
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
178
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
179
    } else {
180
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
181
    }
182
183
    if (!empty($personalSalt)) {
184
        $staticSalt = $personalSalt;
185
    } else {
186
        $staticSalt = SALT;
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
187
    }
188
189
    //set our salt to a variable
190
    // Get 64 random bits for the salt for pbkdf2
191
    $pbkdf2Salt = getBits(64);
192
    // generate a pbkdf2 key to use for the encryption.
193
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
194
    // Build $init_vect and $ivBase64.  We use a block size of 256 bits (AES compliant)
195
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
196
    $init_vect = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_create_iv() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

196
    $init_vect = /** @scrutinizer ignore-deprecated */ mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
Deprecated Code introduced by
The function mcrypt_get_iv_size() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

196
    $init_vect = mcrypt_create_iv(/** @scrutinizer ignore-deprecated */ mcrypt_get_iv_size(MCRYPT_RIJNDAEL_256, 'ctr'), MCRYPT_RAND);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
197
198
    //base64 trim
199
    if (strlen($ivBase64 = rtrim(base64_encode($init_vect), '=')) != 43) {
200
        return false;
201
    }
202
    // Encrypt $decrypted
203
    $encrypted = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $init_vect);
1 ignored issue
show
Deprecated Code introduced by
The function mcrypt_encrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

203
    $encrypted = /** @scrutinizer ignore-deprecated */ mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $key, $decrypted, 'ctr', $init_vect);

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
204
    // MAC the encrypted text
205
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
206
    // We're done!
207
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
208
}
209
210
/**
211
 * decrypt()
212
 *
213
 * decrypt a crypted string
214
 */
215
function decrypt($encrypted, $personalSalt = "")
216
{
217
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
218
219
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
220
        include_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
221
    } else {
222
        include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
223
    }
224
225
    if (!empty($personalSalt)) {
226
        $staticSalt = $personalSalt;
227
    } else {
228
        $staticSalt = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
229
    }
230
    //base64 decode the entire payload
231
    $encrypted = base64_decode($encrypted);
232
    // get the salt
233
    $pbkdf2Salt = substr($encrypted, -64);
234
    //remove the salt from the string
235
    $encrypted = substr($encrypted, 0, -64);
236
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
237
    // Retrieve $init_vect which is the first 22 characters plus ==, base64_decoded.
238
    $init_vect = base64_decode(substr($encrypted, 0, 43).'==');
239
    // Remove $init_vect from $encrypted.
240
    $encrypted = substr($encrypted, 43);
241
    // Retrieve $mac which is the last 64 characters of $encrypted.
242
    $mac = substr($encrypted, -64);
243
    // Remove the last 64 chars from encrypted (remove MAC)
244
    $encrypted = substr($encrypted, 0, -64);
245
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
246
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
247
        return false;
248
    }
249
    // Decrypt the data.
250
    $decrypted = rtrim(mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $init_vect), "\0\4");
0 ignored issues
show
Deprecated Code introduced by
The function mcrypt_decrypt() has been deprecated: 7.1 ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

250
    $decrypted = rtrim(/** @scrutinizer ignore-deprecated */ mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $key, $encrypted, 'ctr', $init_vect), "\0\4");

This function has been deprecated. The supplier of the function has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.

Loading history...
251
    // Yay!
252
    return $decrypted;
253
}
254
255
256
/**
257
 * genHash()
258
 *
259
 * Generate a hash for user login
260
 * @param string $password
261
 */
262
function bCrypt($password, $cost)
263
{
264
    $salt = sprintf('$2y$%02d$', $cost);
265
    if (function_exists('openssl_random_pseudo_bytes')) {
266
        $salt .= bin2hex(openssl_random_pseudo_bytes(11));
267
    } else {
268
        $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
269
        for ($i = 0; $i < 22; $i++) {
270
            $salt .= $chars[mt_rand(0, 63)];
271
        }
272
    }
273
    return crypt($password, $salt);
274
}
275
276
/*
277
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
278
 *
279
 * Using AES_128 and mode CBC
280
 *
281
 * $key and $init_vect have to be given in hex format
282
 */
283
function cryption_phpCrypt($string, $key, $init_vect, $type)
284
{
285
    // manage key origin
286
    if (null != SALT && $key != SALT) {
0 ignored issues
show
Bug introduced by
The constant SALT was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
287
        // check key (AES-128 requires a 16 bytes length key)
288
        if (strlen($key) < 16) {
289
            for ($inc = strlen($key) + 1; $inc <= 16; $inc++) {
290
                $key .= chr(0);
291
            }
292
        } elseif (strlen($key) > 16) {
293
            $key = substr($key, 16);
294
        }
295
    }
296
297
    // load crypt
298
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
299
300
    if ($type == "encrypt") {
301
        // generate IV and encrypt
302
        $init_vect = $crypt->createIV();
303
        $encrypt = $crypt->encrypt($string);
304
        // return
305
        return array(
306
            "string" => bin2hex($encrypt),
307
            "iv" => bin2hex($init_vect),
308
            "error" => empty($encrypt) ? "ERR_ENCRYPTION_NOT_CORRECT" : ""
309
        );
310
    } elseif ($type == "decrypt") {
311
        // case if IV is empty
312
        if (empty($init_vect)) {
313
            return array(
314
                'string' => "",
315
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
316
            );
317
        }
318
319
        // convert
320
        try {
321
            $string = testHex2Bin(trim($string));
322
            $init_vect = testHex2Bin($init_vect);
323
        } catch (Exception $e) {
324
            return array(
325
                'string' => "",
326
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
327
            );
328
        }
329
330
        // load IV
331
        $crypt->IV($init_vect);
332
        // decrypt
333
        $decrypt = $crypt->decrypt($string);
334
        // return
335
        return array(
336
            'string' => str_replace(chr(0), "", $decrypt),
337
            'error' => ""
338
        );
339
    }
340
}
341
342
function testHex2Bin($val)
343
{
344
    if (!@hex2bin($val)) {
345
        throw new Exception("ERROR");
346
    }
347
    return hex2bin($val);
348
}
349
350
/**
351
 * Defuse cryption function
352
 *
353
 * @param  string $message   what to de/crypt
354
 * @param  string $ascii_key key to use
355
 * @param  string $type      operation to perform
356
 * @return array
357
 */
358
function cryption($message, $ascii_key, $type) //defuse_crypto
359
{
360
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
361
362
    // load PhpEncryption library
363
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
364
        $path = '../includes/libraries/Encryption/Encryption/';
365
    } else {
366
        $path = $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
367
    }
368
369
    include_once $path.'Crypto.php';
370
    include_once $path.'Encoding.php';
371
    include_once $path.'DerivedKeys.php';
372
    include_once $path.'Key.php';
373
    include_once $path.'KeyOrPassword.php';
374
    include_once $path.'File.php';
375
    include_once $path.'RuntimeTests.php';
376
    include_once $path.'KeyProtectedByPassword.php';
377
    include_once $path.'Core.php';
378
379
    // init
380
    $err = '';
381
    if (empty($ascii_key)) {
382
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
383
    }
384
385
    // convert KEY
386
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
387
388
    try {
389
        if ($type === "encrypt") {
390
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
391
        } elseif ($type === "decrypt") {
392
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
393
        }
394
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
395
        $err = "an attack! either the wrong key was loaded, or the ciphertext has changed since it was created either corrupted in the database or intentionally modified by someone trying to carry out an attack.";
396
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
397
        $err = $ex;
398
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
399
        $err = $ex;
400
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
401
        $err = $ex;
402
    } catch (Defuse\Crypto\Exception\IOException $ex) {
403
        $err = $ex;
404
    }
405
406
    return array(
407
        'string' => isset($text) ? $text : "",
408
        'error' => $err
409
    );
410
}
411
412
/**
413
 * Generating a defuse key
414
 *
415
 * @return string
416
 */
417
function defuse_generate_key()
418
{
419
    include_once '../includes/libraries/Encryption/Encryption/Crypto.php';
420
    include_once '../includes/libraries/Encryption/Encryption/Encoding.php';
421
    include_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
422
    include_once '../includes/libraries/Encryption/Encryption/Key.php';
423
    include_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
424
    include_once '../includes/libraries/Encryption/Encryption/File.php';
425
    include_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
426
    include_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
427
    include_once '../includes/libraries/Encryption/Encryption/Core.php';
428
429
    $key = \Defuse\Crypto\Key::createNewRandomKey();
430
    $key = $key->saveToAsciiSafeString();
431
    return $key;
432
}
433
434
/**
435
 * Generate a Defuse personal key
436
 *
437
 * @param  string $psk psk used
438
 * @return string
439
 */
440
function defuse_generate_personal_key($psk)
441
{
442
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
443
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
444
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
445
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
446
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
447
    require_once '../includes/libraries/Encryption/Encryption/File.php';
448
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
449
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
450
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
451
452
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
453
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
454
455
    return $protected_key_encoded; // save this in user table
456
}
457
458
/**
459
 * Validate persoanl key with defuse
460
 *
461
 * @param  string $psk                   the user's psk
462
 * @param  string $protected_key_encoded special key
463
 * @return string
464
 */
465
function defuse_validate_personal_key($psk, $protected_key_encoded)
466
{
467
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
468
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
469
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
470
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
471
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
472
    require_once '../includes/libraries/Encryption/Encryption/File.php';
473
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
474
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
475
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
476
477
    try {
478
        $protected_key = \Defuse\Crypto\KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
479
        $user_key = $protected_key->unlockKey($psk);
480
        $user_key_encoded = $user_key->saveToAsciiSafeString();
481
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
482
        return "Error - Major issue as the encryption is broken.";
483
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
484
        return "Error - The saltkey is not the correct one.";
485
    }
486
487
    return $user_key_encoded; // store it in session once user has entered his psk
488
}
489
490
/**
491
 * Decrypt a defuse string if encrypted
492
 *
493
 * @param  string $value Encrypted string
494
 * @return string        Decrypted string
495
 */
496
function defuse_return_decrypted($value)
497
{
498
    if (substr($value, 0, 3) === "def") {
499
        $value = cryption($value, "", "decrypt")['string'];
500
    }
501
    return $value;
502
}
503
504
/**
505
 * trimElement()
506
 *
507
 * trim a string depending on a specific string
508
 * @param  string $chaine  what to trim
509
 * @param  string $element trim on what
510
 * @return string
511
 */
512
function trimElement($chaine, $element)
513
{
514
    if (!empty($chaine)) {
515
        if (is_array($chaine) === true) {
0 ignored issues
show
introduced by
The condition is_array($chaine) === true is always false.
Loading history...
516
            $chaine = implode(";", $chaine);
517
        }
518
        $chaine = trim($chaine);
519
        if (substr($chaine, 0, 1) == $element) {
520
            $chaine = substr($chaine, 1);
521
        }
522
        if (substr($chaine, strlen($chaine) - 1, 1) == $element) {
523
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
524
        }
525
    }
526
    return $chaine;
527
}
528
529
/**
530
 * Permits to suppress all "special" characters from string
531
 *
532
 * @param  string  $string  what to clean
533
 * @param  boolean $special use of special chars?
534
 * @return string
535
 */
536
function cleanString($string, $special = false)
537
{
538
    // Create temporary table for special characters escape
539
    $tabSpecialChar = array();
540
    for ($i = 0; $i <= 31; $i++) {
541
        $tabSpecialChar[] = chr($i);
542
    }
543
    array_push($tabSpecialChar, "<br />");
544
    if ($special == "1") {
545
        $tabSpecialChar = array_merge($tabSpecialChar, array("</li>", "<ul>", "<ol>"));
546
    }
547
548
    return str_replace($tabSpecialChar, "\n", $string);
549
}
550
551
/**
552
 * Erro manager for DB
553
 *
554
 * @param  array $params output from query
555
 * @return void
556
 */
557
function db_error_handler($params)
558
{
559
    echo "Error: ".$params['error']."<br>\n";
560
    echo "Query: ".$params['query']."<br>\n";
561
    throw new Exception("Error - Query", 1);
562
}
563
564
/**
565
 * [identifyUserRights description]
566
 * @param  string $groupesVisiblesUser  [description]
567
 * @param  string $groupesInterditsUser [description]
568
 * @param  string $isAdmin              [description]
569
 * @param  string $idFonctions          [description]
570
 * @return string                       [description]
571
 */
572
function identifyUserRights(
573
    $groupesVisiblesUser,
574
    $groupesInterditsUser,
575
    $isAdmin,
576
    $idFonctions,
577
    $server,
578
    $user,
579
    $pass,
580
    $database,
581
    $port,
582
    $encoding,
583
    $SETTINGS
584
) {
585
    //load ClassLoader
586
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
587
588
    //Connect to DB
589
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
590
    $pass = defuse_return_decrypted($pass);
591
    DB::$host = $server;
592
    DB::$user = $user;
593
    DB::$password = $pass;
594
    DB::$dbName = $database;
595
    DB::$port = $port;
596
    DB::$encoding = $encoding;
597
    DB::$error_handler = true;
598
    $link = mysqli_connect($server, $user, $pass, $database, $port);
599
    $link->set_charset($encoding);
600
601
    //Build tree
602
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
603
    $tree->register();
604
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
605
606
    // Check if user is ADMINISTRATOR
607
    if ($isAdmin === '1') {
608
        $groupesVisibles = array();
609
        $_SESSION['personal_folders'] = array();
610
        $_SESSION['groupes_visibles'] = array();
611
        $_SESSION['groupes_interdits'] = array();
612
        $_SESSION['personal_visible_groups'] = array();
613
        $_SESSION['read_only_folders'] = array();
614
        $_SESSION['list_restricted_folders_for_items'] = array();
615
        $_SESSION['list_folders_editable_by_role'] = array();
616
        $_SESSION['list_folders_limited'] = array();
617
        $_SESSION['no_access_folders'] = array();
618
        $_SESSION['groupes_visibles_list'] = "";
619
        $rows = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i", 0);
620
        foreach ($rows as $record) {
621
            array_push($groupesVisibles, $record['id']);
622
        }
623
        $_SESSION['groupes_visibles'] = $groupesVisibles;
624
        $_SESSION['all_non_personal_folders'] = $groupesVisibles;
625
        // Exclude all PF
626
        $_SESSION['forbiden_pfs'] = array();
627
        $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
628
        $where->add('personal_folder=%i', 1);
629
        if (isset($SETTINGS['enable_pf_feature']) && $SETTINGS['enable_pf_feature'] == 1) {
630
            $where->add('title=%s', $_SESSION['user_id']);
631
            $where->negateLast();
632
        }
633
        // Get ID of personal folder
634
        $persfld = DB::queryfirstrow(
635
            "SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s",
636
            $_SESSION['user_id']
637
        );
638
        if (!empty($persfld['id'])) {
639
            if (!in_array($persfld['id'], $_SESSION['groupes_visibles'])) {
640
                array_push($_SESSION['groupes_visibles'], $persfld['id']);
641
                array_push($_SESSION['personal_visible_groups'], $persfld['id']);
642
                // get all descendants
643
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
644
                $tree->rebuild();
645
                $tst = $tree->getDescendants($persfld['id']);
646
                foreach ($tst as $t) {
647
                    array_push($_SESSION['groupes_visibles'], $t->id);
648
                    array_push($_SESSION['personal_visible_groups'], $t->id);
649
                }
650
            }
651
        }
652
653
        // get complete list of ROLES
654
        $tmp = explode(";", $idFonctions);
655
        $rows = DB::query(
656
            "SELECT * FROM ".prefix_table("roles_title")."
657
            ORDER BY title ASC"
658
        );
659
        foreach ($rows as $record) {
660
            if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
661
                array_push($tmp, $record['id']);
662
            }
663
        }
664
        $_SESSION['fonction_id'] = implode(";", $tmp);
665
666
        $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
667
        $_SESSION['is_admin'] = $isAdmin;
668
        // Check if admin has created Folders and Roles
669
        DB::query("SELECT * FROM ".prefix_table("nested_tree")."");
670
        $_SESSION['nb_folders'] = DB::count();
671
        DB::query("SELECT * FROM ".prefix_table("roles_title"));
672
        $_SESSION['nb_roles'] = DB::count();
673
    } else {
674
        // init
675
        $_SESSION['groupes_visibles'] = array();
676
        $_SESSION['personal_folders'] = array();
677
        $_SESSION['groupes_interdits'] = array();
678
        $_SESSION['personal_visible_groups'] = array();
679
        $_SESSION['read_only_folders'] = array();
680
        $_SESSION['fonction_id'] = $idFonctions;
681
        $groupesInterdits = array();
682
        if (is_array($groupesInterditsUser) === false) {
0 ignored issues
show
introduced by
The condition is_array($groupesInterditsUser) === false is always true.
Loading history...
683
            $groupesInterditsUser = explode(';', trimElement(/** @scrutinizer ignore-type */ $groupesInterditsUser, ";"));
684
        }
685
        if (empty($groupesInterditsUser) === false && count($groupesInterditsUser) > 0) {
686
            $groupesInterdits = $groupesInterditsUser;
687
        }
688
        $_SESSION['is_admin'] = $isAdmin;
689
        $fonctionsAssociees = explode(';', trimElement($idFonctions, ";"));
690
691
        $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
692
693
        // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
694
        foreach ($fonctionsAssociees as $roleId) {
695
            if (empty($roleId) === false) {
696
                // Get allowed folders for each Role
697
                $rows = DB::query(
698
                    "SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id=%i",
699
                    $roleId
700
                );
701
702
                if (DB::count() > 0) {
703
                    $tmp = DB::queryfirstrow(
704
                        "SELECT allow_pw_change FROM ".prefix_table("roles_title")." WHERE id = %i",
705
                        $roleId
706
                    );
707
                    foreach ($rows as $record) {
708
                        if (isset($record['folder_id']) && in_array($record['folder_id'], $listAllowedFolders) === false) {
709
                            array_push($listAllowedFolders, $record['folder_id']);
710
                        }
711
                        // Check if this group is allowed to modify any pw in allowed folders
712
                        if ($tmp['allow_pw_change'] == 1 && in_array($record['folder_id'], $listFoldersEditableByRole) === false) {
713
                            array_push($listFoldersEditableByRole, $record['folder_id']);
714
                        }
715
                    }
716
                    // Check for the users roles if some specific rights exist on items
717
                    $rows = DB::query(
718
                        "SELECT i.id_tree, r.item_id
719
                        FROM ".prefix_table("items")." as i
720
                        INNER JOIN ".prefix_table("restriction_to_roles")." as r ON (r.item_id=i.id)
721
                        WHERE r.role_id=%i
722
                        ORDER BY i.id_tree ASC",
723
                        $roleId
724
                    );
725
                    $inc = 0;
726
                    foreach ($rows as $record) {
727
                        if (isset($record['id_tree'])) {
728
                            $listFoldersLimited[$record['id_tree']][$inc] = $record['item_id'];
729
                            $inc++;
730
                        }
731
                    }
732
                }
733
            }
734
        }
735
        
736
        // Clean arrays
737
        $listAllowedFolders = array_unique($listAllowedFolders);
738
        $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ";"));
739
        
740
        // Does this user is allowed to see other items
741
        $inc = 0;
742
        $rows = DB::query(
743
            "SELECT id, id_tree FROM ".prefix_table("items")."
744
            WHERE restricted_to LIKE %ss AND inactif=%s",
745
            $_SESSION['user_id'].';',
746
            '0'
747
        );
748
        foreach ($rows as $record) {
749
            // Exclude restriction on item if folder is fully accessible
750
            if (in_array($record['id_tree'], $listAllowedFolders) === false) {
751
                $listRestrictedFoldersForItems[$record['id_tree']][$inc] = $record['id'];
752
                $inc++;
753
            }
754
        }
755
        
756
        // => Build final lists
757
        // Add user allowed folders
758
        $allowedFoldersTmp = array_unique(
759
            array_merge($listAllowedFolders, $groupesVisiblesUser)
760
        );
761
        // Exclude from allowed folders all the specific user forbidden folders
762
        $allowedFolders = array();
763
        foreach ($allowedFoldersTmp as $ident) {
764
            if (!in_array($ident, $groupesInterditsUser) && !empty($ident)) {
765
                array_push($allowedFolders, $ident);
766
            }
767
        }
768
769
        // Clean array
770
        $listAllowedFolders = array_filter(array_unique($allowedFolders));
771
772
        // Exclude all PF
773
        $_SESSION['forbiden_pfs'] = array();
774
775
        $where = new WhereClause('and');
776
        $where->add('personal_folder=%i', 1);
777
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
778
            && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
779
        ) {
780
            $where->add('title=%s', $_SESSION['user_id']);
781
            $where->negateLast();
782
        }
783
784
        $persoFlds = DB::query(
785
            "SELECT id
786
            FROM ".prefix_table("nested_tree")."
787
            WHERE %l",
788
            $where
789
        );
790
        foreach ($persoFlds as $persoFldId) {
791
            array_push($_SESSION['forbiden_pfs'], $persoFldId['id']);
792
        }
793
        // Get IDs of personal folders
794
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
795
            && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
796
        ) {
797
            $persoFld = DB::queryfirstrow(
798
                "SELECT id
799
                FROM ".prefix_table("nested_tree")."
800
                WHERE title = %s AND personal_folder = %i",
801
                $_SESSION['user_id'],
802
                1
803
            );
804
            if (empty($persoFld['id']) === false) {
805
                if (in_array($persoFld['id'], $listAllowedFolders) === false) {
806
                    array_push($_SESSION['personal_folders'], $persoFld['id']);
807
                    array_push($listAllowedFolders, $persoFld['id']);
808
                    array_push($_SESSION['personal_visible_groups'], $persoFld['id']);
809
                    // get all descendants
810
                    $ids = $tree->getChildren($persoFld['id']);
811
                    foreach ($ids as $ident) {
812
                        array_push($listAllowedFolders, $ident->id);
813
                        array_push($_SESSION['personal_visible_groups'], $ident->id);
814
                        array_push($_SESSION['personal_folders'], $ident->id);
815
                    }
816
                }
817
            }
818
            // get list of readonly folders when pf is disabled.
819
            $_SESSION['personal_folders'] = array_unique($_SESSION['personal_folders']);
820
            // rule - if one folder is set as W or N in one of the Role, then User has access as W
821
            foreach ($listAllowedFolders as $folderId) {
822
                if (in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders']))) === false) {
823
                    DB::query(
824
                        "SELECT *
825
                        FROM ".prefix_table("roles_values")."
826
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
827
                        $folderId,
828
                        $fonctionsAssociees,
829
                        array("W", "ND", "NE", "NDNE")
830
                    );
831
                    if (DB::count() === 0 && in_array($folderId, $groupesVisiblesUser) === false) {
832
                        array_push($listReadOnlyFolders, $folderId);
833
                    }
834
                }
835
            }
836
        } else {
837
            // get list of readonly folders when pf is disabled.
838
            // rule - if one folder is set as W in one of the Role, then User has access as W
839
            foreach ($listAllowedFolders as $folderId) {
840
                if (in_array($folderId, $listReadOnlyFolders) === false) {
841
                    DB::query(
842
                        "SELECT *
843
                        FROM ".prefix_table("roles_values")."
844
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
845
                        $folderId,
846
                        $fonctionsAssociees,
847
                        array("W", "ND", "NE", "NDNE")
848
                    );
849
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
850
                        array_push($listReadOnlyFolders, $folderId);
851
                    }
852
                }
853
            }
854
        }
855
856
        // check if change proposals on User's items
857
        if (isset($SETTINGS['enable_suggestion']) === true && $SETTINGS['enable_suggestion'] === '1') {
858
            DB::query(
859
                "SELECT *
860
                FROM ".prefix_table("items_change")." AS c
861
                LEFT JOIN ".prefix_table("log_items")." AS i ON (c.item_id = i.id_item)
862
                WHERE i.action = %s AND i.id_user = %i",
863
                "at_creation",
864
                $_SESSION['user_id']
865
            );
866
            $_SESSION['nb_item_change_proposals'] = DB::count();
867
        } else {
868
            $_SESSION['nb_item_change_proposals'] = 0;
869
        }
870
871
        $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
872
        $_SESSION['groupes_visibles'] = $listAllowedFolders;
873
        $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
874
        $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
875
        $_SESSION['read_only_folders'] = $listReadOnlyFolders;
876
        $_SESSION['no_access_folders'] = $groupesInterdits;
877
878
        $_SESSION['list_folders_limited'] = $listFoldersLimited;
879
        $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
880
        $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
881
        // Folders and Roles numbers
882
        DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")."");
883
        $_SESSION['nb_folders'] = DB::count();
884
        DB::queryfirstrow("SELECT id FROM ".prefix_table("roles_title"));
885
        $_SESSION['nb_roles'] = DB::count();
886
    }
887
888
    // update user's timestamp
889
    DB::update(
890
        prefix_table('users'),
891
        array(
892
            'timestamp' => time()
893
        ),
894
        "id=%i",
895
        $_SESSION['user_id']
896
    );
897
}
898
899
/**
900
 * updateCacheTable()
901
 *
902
 * Update the CACHE table
903
 * @param string $action
904
 */
905
function updateCacheTable($action, $ident = "")
906
{
907
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
908
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
909
910
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
911
912
    //Connect to DB
913
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
914
    $pass = defuse_return_decrypted($pass);
915
    DB::$host = $server;
916
    DB::$user = $user;
917
    DB::$password = $pass;
918
    DB::$dbName = $database;
919
    DB::$port = $port;
920
    DB::$encoding = $encoding;
921
    DB::$error_handler = true;
922
    $link = mysqli_connect($server, $user, $pass, $database, $port);
923
    $link->set_charset($encoding);
924
925
    //Load Tree
926
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
927
    $tree->register();
928
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
929
930
    // Rebuild full cache table
931
    if ($action === "reload") {
932
        // truncate table
933
        DB::query("TRUNCATE TABLE ".prefix_table("cache"));
934
935
        // reload date
936
        $rows = DB::query(
937
            "SELECT *
938
            FROM ".prefix_table('items')." as i
939
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
940
            AND l.action = %s
941
            AND i.inactif = %i",
942
            'at_creation',
943
            0
944
        );
945
        foreach ($rows as $record) {
946
            if (empty($record['id_tree']) === false) {
947
                // Get all TAGS
948
                $tags = "";
949
                $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $record['id']);
950
                foreach ($itemTags as $itemTag) {
951
                    if (!empty($itemTag['tag'])) {
952
                        $tags .= $itemTag['tag']." ";
953
                    }
954
                }
955
                // Get renewal period
956
                $resNT = DB::queryfirstrow("SELECT renewal_period FROM ".prefix_table('nested_tree')." WHERE id=%i", $record['id_tree']);
957
958
                // form id_tree to full foldername
959
                $folder = "";
960
                $arbo = $tree->getPath($record['id_tree'], true);
961
                foreach ($arbo as $elem) {
962
                    if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
963
                        $elem->title = $_SESSION['login'];
964
                    }
965
                    if (empty($folder)) {
966
                        $folder = stripslashes($elem->title);
967
                    } else {
968
                        $folder .= " » ".stripslashes($elem->title);
969
                    }
970
                }
971
                // store data
972
                DB::insert(
973
                    prefix_table('cache'),
974
                    array(
975
                        'id' => $record['id'],
976
                        'label' => $record['label'],
977
                        'description' => isset($record['description']) ? $record['description'] : "",
978
                        'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : "0",
979
                        'tags' => $tags,
980
                        'id_tree' => $record['id_tree'],
981
                        'perso' => $record['perso'],
982
                        'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : "0",
983
                        'login' => isset($record['login']) ? $record['login'] : "",
984
                        'folder' => $folder,
985
                        'author' => $record['id_user'],
986
                        'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : "0",
987
                        'timestamp' => $record['date']
988
                        )
989
                );
990
            }
991
        }
992
        // UPDATE an item
993
    } elseif ($action === "update_value") {
994
        // get new value from db
995
        $data = DB::queryfirstrow(
996
            "SELECT label, description, id_tree, perso, restricted_to, login, url
997
            FROM ".prefix_table('items')."
998
            WHERE id=%i",
999
            $ident
1000
        );
1001
        // Get all TAGS
1002
        $tags = "";
1003
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $ident);
1004
        foreach ($itemTags as $itemTag) {
1005
            if (!empty($itemTag['tag'])) {
1006
                $tags .= $itemTag['tag']." ";
1007
            }
1008
        }
1009
        // form id_tree to full foldername
1010
        $folder = "";
1011
        $arbo = $tree->getPath($data['id_tree'], true);
1012
        foreach ($arbo as $elem) {
1013
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1014
                $elem->title = $_SESSION['login'];
1015
            }
1016
            if (empty($folder)) {
1017
                $folder = stripslashes($elem->title);
1018
            } else {
1019
                $folder .= " » ".stripslashes($elem->title);
1020
            }
1021
        }
1022
        // finaly update
1023
        DB::update(
1024
            prefix_table('cache'),
1025
            array(
1026
                'label' => $data['label'],
1027
                'description' => $data['description'],
1028
                'tags' => $tags,
1029
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1030
                'id_tree' => $data['id_tree'],
1031
                'perso' => $data['perso'],
1032
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1033
                'login' => isset($data['login']) ? $data['login'] : "",
1034
                'folder' => $folder,
1035
                'author' => $_SESSION['user_id'],
1036
                ),
1037
            "id = %i",
1038
            $ident
1039
        );
1040
    // ADD an item
1041
    } elseif ($action === "add_value") {
1042
        // get new value from db
1043
        $data = DB::queryFirstRow(
1044
            "SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
1045
            FROM ".prefix_table('items')." as i
1046
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
1047
            WHERE i.id = %i
1048
            AND l.action = %s",
1049
            $ident,
1050
            'at_creation'
1051
        );
1052
        // Get all TAGS
1053
        $tags = "";
1054
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id = %i", $ident);
1055
        foreach ($itemTags as $itemTag) {
1056
            if (!empty($itemTag['tag'])) {
1057
                $tags .= $itemTag['tag']." ";
1058
            }
1059
        }
1060
        // form id_tree to full foldername
1061
        $folder = "";
1062
        $arbo = $tree->getPath($data['id_tree'], true);
1063
        foreach ($arbo as $elem) {
1064
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1065
                $elem->title = $_SESSION['login'];
1066
            }
1067
            if (empty($folder)) {
1068
                $folder = stripslashes($elem->title);
1069
            } else {
1070
                $folder .= " » ".stripslashes($elem->title);
1071
            }
1072
        }
1073
        // finaly update
1074
        DB::insert(
1075
            prefix_table('cache'),
1076
            array(
1077
                'id' => $data['id'],
1078
                'label' => $data['label'],
1079
                'description' => $data['description'],
1080
                'tags' => (isset($tags) && !empty($tags)) ? $tags : "None",
1081
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1082
                'id_tree' => $data['id_tree'],
1083
                'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== "None") ? $data['perso'] : "0",
1084
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1085
                'login' => isset($data['login']) ? $data['login'] : "",
1086
                'folder' => $folder,
1087
                'author' => $_SESSION['user_id'],
1088
                'timestamp' => $data['date']
1089
            )
1090
        );
1091
1092
    // DELETE an item
1093
    } elseif ($action === "delete_value") {
1094
        DB::delete(prefix_table('cache'), "id = %i", $ident);
1095
    }
1096
}
1097
1098
/*
1099
*
1100
*/
1101
function getStatisticsData()
1102
{
1103
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1104
1105
    DB::query(
1106
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1107
        0
1108
    );
1109
    $counter_folders = DB::count();
1110
1111
    DB::query(
1112
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1113
        1
1114
    );
1115
    $counter_folders_perso = DB::count();
1116
1117
    DB::query(
1118
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1119
        0
1120
    );
1121
    $counter_items = DB::count();
1122
1123
    DB::query(
1124
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1125
        1
1126
    );
1127
    $counter_items_perso = DB::count();
1128
1129
    DB::query(
1130
        "SELECT id FROM ".prefix_table("users").""
1131
    );
1132
    $counter_users = DB::count();
1133
1134
    DB::query(
1135
        "SELECT id FROM ".prefix_table("users")." WHERE admin = %i",
1136
        1
1137
    );
1138
    $admins = DB::count();
1139
1140
    DB::query(
1141
        "SELECT id FROM ".prefix_table("users")." WHERE gestionnaire = %i",
1142
        1
1143
    );
1144
    $managers = DB::count();
1145
1146
    DB::query(
1147
        "SELECT id FROM ".prefix_table("users")." WHERE read_only = %i",
1148
        1
1149
    );
1150
    $readOnly = DB::count();
1151
1152
    // list the languages
1153
    $usedLang = [];
1154
    $tp_languages = DB::query(
1155
        "SELECT name FROM ".prefix_table("languages")
1156
    );
1157
    foreach ($tp_languages as $tp_language) {
1158
        DB::query(
1159
            "SELECT * FROM ".prefix_table("users")." WHERE user_language = %s",
1160
            $tp_language['name']
1161
        );
1162
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1163
    }
1164
1165
    // get list of ips
1166
    $usedIp = [];
1167
    $tp_ips = DB::query(
1168
        "SELECT user_ip FROM ".prefix_table("users")
1169
    );
1170
    foreach ($tp_ips as $ip) {
1171
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1172
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1173
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== "none") {
1174
            $usedIp[$ip['user_ip']] = 1;
1175
        }
1176
    }
1177
1178
    return array(
1179
        "error" => "",
1180
        "stat_phpversion" => phpversion(),
1181
        "stat_folders" => $counter_folders,
1182
        "stat_folders_shared" => intval($counter_folders) - intval($counter_folders_perso),
1183
        "stat_items" => $counter_items,
1184
        "stat_items_shared" => intval($counter_items) - intval($counter_items_perso),
1185
        "stat_users" => $counter_users,
1186
        "stat_admins" => $admins,
1187
        "stat_managers" => $managers,
1188
        "stat_ro" => $readOnly,
1189
        "stat_kb" => $SETTINGS['enable_kb'],
1190
        "stat_pf" => $SETTINGS['enable_pf_feature'],
1191
        "stat_fav" => $SETTINGS['enable_favourites'],
1192
        "stat_teampassversion" => $SETTINGS['cpassman_version'],
1193
        "stat_ldap" => $SETTINGS['ldap_mode'],
1194
        "stat_agses" => $SETTINGS['agses_authentication_enabled'],
1195
        "stat_duo" => $SETTINGS['duo'],
1196
        "stat_suggestion" => $SETTINGS['enable_suggestion'],
1197
        "stat_api" => $SETTINGS['api'],
1198
        "stat_customfields" => $SETTINGS['item_extra_fields'],
1199
        "stat_syslog" => $SETTINGS['syslog_enable'],
1200
        "stat_2fa" => $SETTINGS['google_authentication'],
1201
        "stat_stricthttps" => $SETTINGS['enable_sts'],
1202
        "stat_mysqlversion" => DB::serverVersion(),
1203
        "stat_languages" => $usedLang,
1204
        "stat_country" => $usedIp
1205
    );
1206
}
1207
1208
/**
1209
 * Permits to send an email
1210
 *
1211
 * @param  string $subject     email subject
1212
 * @param  string $textMail    email message
1213
 * @param  string $email       email
1214
 * @param  array  $LANG        Language
1215
 * @param  array  $SETTINGS    settings
1216
 * @param  string $textMailAlt email message alt
1217
 * @return  string  some json info
1218
 */
1219
function sendEmail(
1220
    $subject,
1221
    $textMail,
1222
    $email,
1223
    $LANG,
1224
    $SETTINGS,
1225
    $textMailAlt = ""
1226
) {
1227
    // CAse where email not defined
1228
    if ($email === "none") {
1229
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1230
    }
1231
1232
    // Load settings
1233
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
1234
1235
    // Load superglobal
1236
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1237
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
1238
1239
    // Get user language
1240
    $session_user_language = $superGlobal->get("user_language", "SESSION");
1241
    $user_language = isset($session_user_language) ? $session_user_language : "english";
1242
    require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1243
1244
    // Load library
1245
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1246
1247
    // load PHPMailer
1248
    $mail = new SplClassLoader('Email\PHPMailer', '../includes/libraries');
1249
    $mail->register();
1250
    $mail = new Email\PHPMailer\PHPMailer(true);
1251
    try {
1252
        // send to user
1253
        $mail->setLanguage("en", $SETTINGS['cpassman_dir']."/includes/libraries/Email/PHPMailer/language/");
1254
        $mail->SMTPDebug = 0; //value 1 can be used to debug - 4 for debuging connections
1255
        $mail->Port = $SETTINGS['email_port']; //COULD BE USED
1256
        $mail->CharSet = "utf-8";
1257
        if ($SETTINGS['email_security'] === "tls" || $SETTINGS['email_security'] === "ssl") {
1258
            $mail->SMTPSecure = $SETTINGS['email_security'];
1259
            $SMTPAutoTLS = true;
1260
        } else {
1261
            $SMTPAutoTLS = false;
1262
            $mail->SMTPSecure = "";
1263
        }
1264
        $mail->SMTPAutoTLS = $SMTPAutoTLS;
1265
        $mail->isSmtp(); // send via SMTP
1266
        $mail->Host = $SETTINGS['email_smtp_server']; // SMTP servers
1267
        $mail->SMTPAuth = $SETTINGS['email_smtp_auth'] == '1' ? true : false; // turn on SMTP authentication
1268
        $mail->Username = $SETTINGS['email_auth_username']; // SMTP username
1269
        $mail->Password = $SETTINGS['email_auth_pwd']; // SMTP password
1270
        $mail->From = $SETTINGS['email_from'];
1271
        $mail->FromName = $SETTINGS['email_from_name'];
1272
1273
        // Prepare for each person
1274
        $dests = explode(",", $email);
1275
        foreach ($dests as $dest) {
1276
            $mail->addAddress($dest);
1277
        }
1278
1279
        // Prepare HTML
1280
        $text_html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.=
1281
        w3.org/TR/html4/loose.dtd"><html>
1282
        <head><title>Email Template</title>
1283
        <style type="text/css">
1284
        body { background-color: #f0f0f0; padding: 10px 0; margin:0 0 10px =0; }
1285
        </style></head>
1286
        <body style="-ms-text-size-adjust: none; size-adjust: none; margin: 0; padding: 10px 0; background-color: #f0f0f0;" bgcolor="#f0f0f0" leftmargin="0" topmargin="0" marginwidth="0" marginheight="0">
1287
        <table border="0" width="100%" height="100%" cellpadding="0" cellspacing="0" bgcolor="#f0f0f0" style="border-spacing: 0;">
1288
        <tr><td style="border-collapse: collapse;"><br>
1289
            <table border="0" width="100%" cellpadding="0" cellspacing="0" bgcolor="#17357c" style="border-spacing: 0; margin-bottom: 25px;">
1290
            <tr><td style="border-collapse: collapse; padding: 11px 20px;">
1291
                <div style="max-width:150px; max-height:34px; color:#f0f0f0; font-weight:bold;">Teampass</div>
1292
            </td></tr></table></td>
1293
        </tr>
1294
        <tr><td align="center" valign="top" bgcolor="#f0f0f0" style="border-collapse: collapse; background-color: #f0f0f0;">
1295
            <table width="600" cellpadding="0" cellspacing="0" border="0" class="container" bgcolor="#ffffff" style="border-spacing: 0; border-bottom: 1px solid #e0e0e0; box-shadow: 0 0 3px #ddd; color: #434343; font-family: Helvetica, Verdana, sans-serif;">
1296
            <tr><td class="container-padding" bgcolor="#ffffff" style="border-collapse: collapse; border-left: 1px solid #e0e0e0; background-color: #ffffff; padding-left: 30px; padding-right: 30px;">
1297
            <br><div style="float:right;">'.
1298
        $textMail.
1299
        '<br><br></td></tr></table>
1300
        </td></tr></table>
1301
        <br></body></html>';
1302
1303
        $mail->WordWrap = 80; // set word wrap
1304
        $mail->isHtml(true); // send as HTML
1305
        $mail->Subject = $subject;
1306
        $mail->Body = $text_html;
1307
        $mail->AltBody = $textMailAlt;
1308
        // send email
1309
        if (!$mail->send()) {
1310
            return '"error":"error_mail_not_send" , "message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1311
        } else {
1312
            return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1313
        }
1314
    } catch (Exception $e) {
1315
        return '"error":"error_mail_not_send" , '.
1316
        '"message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1317
    }
1318
}
1319
1320
/**
1321
 * generateKey()
1322
 *
1323
 * @return
1324
 */
1325
function generateKey()
1326
{
1327
    return substr(md5(rand().rand()), 0, 15);
1328
}
1329
1330
/**
1331
 * dateToStamp()
1332
 *
1333
 * @return
1334
 */
1335
function dateToStamp($date)
1336
{
1337
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1338
1339
    $date = date_parse_from_format($SETTINGS['date_format'], $date);
1340
    if ($date['warning_count'] == 0 && $date['error_count'] == 0) {
1341
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1342
    } else {
1343
        return false;
1344
    }
1345
}
1346
1347
function isDate($date)
1348
{
1349
    return (strtotime($date) !== false);
1350
}
1351
1352
/**
1353
 * isUTF8()
1354
 *
1355
 * @return integer is the string in UTF8 format.
1356
 */
1357
1358
function isUTF8($string)
1359
{
1360
    if (is_array($string) === true) {
1361
        $string = $string['string'];
1362
    }
1363
    return preg_match(
1364
        '%^(?:
1365
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1366
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1367
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1368
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1369
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1370
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1371
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1372
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1373
        )*$%xs',
1374
        $string
1375
    );
1376
}
1377
1378
/*
1379
* FUNCTION
1380
* permits to prepare data to be exchanged
1381
*/
1382
/**
1383
 * @param string $type
1384
 */
1385
function prepareExchangedData($data, $type)
1386
{
1387
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1388
1389
    //load ClassLoader
1390
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1391
    //Load AES
1392
    $aes = new SplClassLoader('Encryption\Crypt', $SETTINGS['cpassman_dir'].'/includes/libraries');
1393
    $aes->register();
1394
1395
    if ($type == "encode") {
1396
        if (isset($SETTINGS['encryptClientServer'])
1397
            && $SETTINGS['encryptClientServer'] === "0"
1398
        ) {
1399
            return json_encode(
1400
                $data,
1401
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1402
            );
1403
        } else {
1404
            return Encryption\Crypt\aesctr::encrypt(
1405
                json_encode(
1406
                    $data,
1407
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1408
                ),
1409
                $_SESSION['key'],
1410
                256
1411
            );
1412
        }
1413
    } elseif ($type == "decode") {
1414
        if (isset($SETTINGS['encryptClientServer'])
1415
            && $SETTINGS['encryptClientServer'] === "0"
1416
        ) {
1417
            return json_decode(
1418
                $data,
1419
                true
1420
            );
1421
        } else {
1422
            return json_decode(
1423
                Encryption\Crypt\aesctr::decrypt(
1424
                    $data,
1425
                    $_SESSION['key'],
1426
                    256
1427
                ),
1428
                true
1429
            );
1430
        }
1431
    }
1432
}
1433
1434
function make_thumb($src, $dest, $desired_width)
1435
{
1436
    /* read the source image */
1437
    $source_image = imagecreatefrompng($src);
1438
    $width = imagesx($source_image);
1439
    $height = imagesy($source_image);
1440
1441
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1442
    $desired_height = floor($height * ($desired_width / $width));
1443
1444
    /* create a new, "virtual" image */
1445
    $virtual_image = imagecreatetruecolor($desired_width, $desired_height);
0 ignored issues
show
Bug introduced by
$desired_height of type double is incompatible with the type integer expected by parameter $height of imagecreatetruecolor(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1445
    $virtual_image = imagecreatetruecolor($desired_width, /** @scrutinizer ignore-type */ $desired_height);
Loading history...
1446
1447
    /* copy source image at a resized size */
1448
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, $desired_height, $width, $height);
0 ignored issues
show
Bug introduced by
$desired_height of type double is incompatible with the type integer expected by parameter $dst_h of imagecopyresampled(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

1448
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, /** @scrutinizer ignore-type */ $desired_height, $width, $height);
Loading history...
1449
1450
    /* create the physical thumbnail image to its destination */
1451
    imagejpeg($virtual_image, $dest);
1452
}
1453
1454
/*
1455
** check table prefix in SQL query
1456
*/
1457
/**
1458
 * @param string $table
1459
 */
1460
function prefix_table($table)
1461
{
1462
    global $pre;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1463
    $safeTable = htmlspecialchars($pre.$table);
1464
    if (!empty($safeTable)) {
1465
        // sanitize string
1466
        return $safeTable;
1467
    } else {
1468
        // stop error no table
1469
        return "table_not_exists";
1470
    }
1471
}
1472
1473
/*
1474
 * Creates a KEY using PasswordLib
1475
 */
1476
function GenerateCryptKey($size = "", $secure = false, $numerals = false, $capitalize = false, $symbols = false)
1477
{
1478
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1479
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1480
1481
    if ($secure === true) {
1482
        $numerals = true;
1483
        $capitalize = true;
1484
        $symbols = true;
1485
    }
1486
1487
    // Load libraries
1488
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
1489
    $generator->register();
1490
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
1491
1492
    // Can we use PHP7 random_int function?
1493
    if (version_compare(phpversion(), '7.0', '>=')) {
1494
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/PasswordGenerator/RandomGenerator/Php7RandomGenerator.php';
1495
        $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
1496
    }
1497
1498
    // init
1499
    if (empty($size) === false) {
1500
        $generator->setLength(intval($size));
1501
    }
1502
    if (empty($numerals) === false) {
1503
        $generator->setNumbers($numerals);
1504
    }
1505
    if (empty($capitalize) === false) {
1506
        $generator->setUppercase($capitalize);
1507
    }
1508
    if (empty($symbols) === false) {
1509
        $generator->setSymbols($symbols);
1510
    }
1511
1512
    // generate and send back
1513
    return $generator->generatePassword();
1514
}
1515
1516
/*
1517
* Send sysLOG message
1518
* @param string $message
1519
* @param string $host
1520
*/
1521
function send_syslog($message, $host, $port, $component = "teampass")
1522
{
1523
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1524
    $syslog_message = "<123>".date('M d H:i:s ').$component.": ".$message;
1525
    socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1526
    socket_close($sock);
1527
}
1528
1529
1530
1531
/**
1532
 * logEvents()
1533
 *
1534
 * permits to log events into DB
1535
 * @param string $type
1536
 * @param string $label
1537
 * @param string $field_1
1538
 */
1539
function logEvents($type, $label, $who, $login = "", $field_1 = null)
1540
{
1541
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1542
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1543
1544
    if (empty($who)) {
1545
        $who = get_client_ip_server();
1546
    }
1547
1548
    // include librairies & connect to DB
1549
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1550
    $pass = defuse_return_decrypted($pass);
1551
    DB::$host = $server;
1552
    DB::$user = $user;
1553
    DB::$password = $pass;
1554
    DB::$dbName = $database;
1555
    DB::$port = $port;
1556
    DB::$encoding = $encoding;
1557
    DB::$error_handler = true;
1558
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1559
    $link->set_charset($encoding);
1560
1561
    DB::insert(
1562
        prefix_table("log_system"),
1563
        array(
1564
            'type' => $type,
1565
            'date' => time(),
1566
            'label' => $label,
1567
            'qui' => $who,
1568
            'field_1' => $field_1 === null ? "" : $field_1
1569
        )
1570
    );
1571
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1572
        if ($type == "user_mngt") {
1573
            send_syslog(
1574
                'action='.str_replace('at_', '', $label).' attribute=user user='.$who.' userid="'.$login.'" change="'.$field_1.'" ',
1575
                $SETTINGS['syslog_host'],
1576
                $SETTINGS['syslog_port'],
1577
                "teampass"
1578
            );
1579
        } else {
1580
            send_syslog(
1581
                'action='.$type.' attribute='.$label.' user='.$who.' userid="'.$login.'" ',
1582
                $SETTINGS['syslog_host'],
1583
                $SETTINGS['syslog_port'],
1584
                "teampass"
1585
            );
1586
        }
1587
    }
1588
}
1589
1590
/**
1591
 * Logs sent events
1592
 *
1593
 * @param string $ident
1594
 * @param string $item
1595
 * @param string $id_user
1596
 * @param string $action
1597
 * @param string $login
1598
 * @param string $raison
1599
 * @param string $encryption_type
1600
 * @return void
1601
 */
1602
function logItems(
1603
    $item_id,
1604
    $item_label,
1605
    $id_user,
1606
    $action,
1607
    $login = "",
1608
    $raison = null,
1609
    $encryption_type = ""
1610
) {
1611
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1612
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1613
    $dataItem = '';
1614
1615
    // include librairies & connect to DB
1616
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1617
    $pass = defuse_return_decrypted($pass);
1618
    DB::$host = $server;
1619
    DB::$user = $user;
1620
    DB::$password = $pass;
1621
    DB::$dbName = $database;
1622
    DB::$port = $port;
1623
    DB::$encoding = $encoding;
1624
    DB::$error_handler = true;
1625
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1626
    $link->set_charset($encoding);
1627
1628
    // Insert log in DB
1629
    DB::insert(
1630
        prefix_table("log_items"),
1631
        array(
1632
            'id_item' => $item_id,
1633
            'date' => time(),
1634
            'id_user' => $id_user,
1635
            'action' => $action,
1636
            'raison' => $raison,
1637
            'raison_iv' => '',
1638
            'encryption_type' => $encryption_type
1639
        )
1640
    );
1641
1642
    // SYSLOG
1643
    if (isset($SETTINGS['syslog_enable']) === true && $SETTINGS['syslog_enable'] === '1') {
1644
        // Extract reason
1645
        $attribute = explode(' : ', $raison);
1646
1647
        // Get item info if not known
1648
        if (empty($item_label) === true) {
1649
            $dataItem = DB::queryfirstrow(
1650
                "SELECT id, id_tree, label
1651
                FROM ".prefix_table("items")."
1652
                WHERE id = %i",
1653
                $item_id
1654
            );
1655
1656
            $item_label = $dataItem['label'];
1657
        }
1658
1659
        send_syslog(
1660
            'action='.str_replace('at_', '', $action).' attribute='.str_replace('at_', '', $attribute[0]).' itemno='.$item_id.' user='.addslashes($login).' itemname="'.addslashes($item_label).'"',
1661
            $SETTINGS['syslog_host'],
1662
            $SETTINGS['syslog_port'],
1663
            "teampass"
1664
        );
1665
    }
1666
1667
    // send notification if enabled
1668
    if (isset($SETTINGS['enable_email_notification_on_item_shown']) === true
1669
        && $SETTINGS['enable_email_notification_on_item_shown'] === '1'
1670
        && $action === 'at_shown'
1671
    ) {
1672
        // Get info about item
1673
        if (empty($dataItem) === true && empty($item_label) === true) {
1674
            $dataItem = DB::queryfirstrow(
1675
                "SELECT id, id_tree, label
1676
                FROM ".prefix_table("items")."
1677
                WHERE id = %i",
1678
                $item_id
1679
            );
1680
            $item_label = $dataItem['label'];
1681
        }
1682
1683
        // send back infos
1684
        DB::insert(
1685
            prefix_table('emails'),
1686
            array(
1687
                'timestamp' => time(),
1688
                'subject' => $LANG['email_on_open_notification_subject'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $LANG seems to be never defined.
Loading history...
1689
                'body' => str_replace(
1690
                    array('#tp_user#', '#tp_item#', '#tp_link#'),
1691
                    array(
1692
                        addslashes($_SESSION['login']),
1693
                        addslashes($item_label),
1694
                        $SETTINGS['cpassman_url']."/index.php?page=items&group=".$dataItem['id_tree']."&id=".$dataItem['id']
1695
                    ),
1696
                    $LANG['email_on_open_notification_mail']
1697
                ),
1698
                'receivers' => $_SESSION['listNotificationEmails'],
1699
                'status' => ''
1700
            )
1701
        );
1702
    }
1703
}
1704
1705
/*
1706
* Function to get the client ip address
1707
 */
1708
function get_client_ip_server()
1709
{
1710
    if (getenv('HTTP_CLIENT_IP')) {
1711
        $ipaddress = getenv('HTTP_CLIENT_IP');
1712
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1713
        $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1714
    } elseif (getenv('HTTP_X_FORWARDED')) {
1715
        $ipaddress = getenv('HTTP_X_FORWARDED');
1716
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1717
        $ipaddress = getenv('HTTP_FORWARDED_FOR');
1718
    } elseif (getenv('HTTP_FORWARDED')) {
1719
        $ipaddress = getenv('HTTP_FORWARDED');
1720
    } elseif (getenv('REMOTE_ADDR')) {
1721
        $ipaddress = getenv('REMOTE_ADDR');
1722
    } else {
1723
        $ipaddress = 'UNKNOWN';
1724
    }
1725
1726
    return $ipaddress;
1727
}
1728
1729
/**
1730
 * Escape all HTML, JavaScript, and CSS
1731
 *
1732
 * @param string $input The input string
1733
 * @param string $encoding Which character encoding are we using?
1734
 * @return string
1735
 */
1736
function noHTML($input, $encoding = 'UTF-8')
1737
{
1738
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1739
}
1740
1741
/**
1742
 * handleConfigFile()
1743
 *
1744
 * permits to handle the Teampass config file
1745
 * $action accepts "rebuild" and "update"
1746
 */
1747
function handleConfigFile($action, $field = null, $value = null)
1748
{
1749
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1750
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1751
1752
    $tp_config_file = "../includes/config/tp.config.php";
1753
1754
    // include librairies & connect to DB
1755
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1756
    $pass = defuse_return_decrypted($pass);
1757
    DB::$host = $server;
1758
    DB::$user = $user;
1759
    DB::$password = $pass;
1760
    DB::$dbName = $database;
1761
    DB::$port = $port;
1762
    DB::$encoding = $encoding;
1763
    DB::$error_handler = true;
1764
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1765
    $link->set_charset($encoding);
1766
1767
    if (!file_exists($tp_config_file) || $action == "rebuild") {
1768
        // perform a copy
1769
        if (file_exists($tp_config_file)) {
1770
            if (!copy($tp_config_file, $tp_config_file.'.'.date("Y_m_d_His", time()))) {
1771
                return "ERROR: Could not copy file '".$tp_config_file."'";
1772
            }
1773
        }
1774
1775
        // regenerate
1776
        $data = array();
1777
        $data[0] = "<?php\n";
1778
        $data[1] = "global \$SETTINGS;\n";
1779
        $data[2] = "\$SETTINGS = array (\n";
1780
        $rows = DB::query(
1781
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s",
1782
            "admin"
1783
        );
1784
        foreach ($rows as $record) {
1785
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
1786
        }
1787
        array_push($data, ");\n");
1788
        $data = array_unique($data);
1789
    } elseif ($action == "update" && empty($field) === false) {
1790
        $data = file($tp_config_file);
1791
        $inc = 0;
1792
        $bFound = false;
1793
        foreach ($data as $line) {
1794
            if (stristr($line, ");")) {
1795
                break;
1796
            }
1797
1798
            //
1799
            if (stristr($line, "'".$field."' => '")) {
1800
                $data[$inc] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n";
1801
                $bFound = true;
1802
                break;
1803
            }
1804
            $inc++;
1805
        }
1806
        if ($bFound === false) {
1807
            $data[($inc)] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n);\n";
1808
        }
1809
    }
1810
1811
    // update file
1812
    file_put_contents($tp_config_file, implode('', isset($data) ? $data : array()));
1813
1814
    return true;
1815
}
1816
1817
/*
1818
** Permits to replace &#92; to permit correct display
1819
*/
1820
/**
1821
 * @param string $input
1822
 */
1823
function handleBackslash($input)
1824
{
1825
    return str_replace("&amp;#92;", "&#92;", $input);
1826
}
1827
1828
/*
1829
** Permits to loas settings
1830
*/
1831
function loadSettings()
1832
{
1833
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1834
1835
    /* LOAD CPASSMAN SETTINGS */
1836
    if (!isset($SETTINGS['loaded']) || $SETTINGS['loaded'] != 1) {
1837
        $SETTINGS['duplicate_folder'] = 0; //by default, this is set to 0;
1838
        $SETTINGS['duplicate_item'] = 0; //by default, this is set to 0;
1839
        $SETTINGS['number_of_used_pw'] = 5; //by default, this value is set to 5;
1840
        $settings = array();
1841
1842
        $rows = DB::query(
1843
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s_type OR type=%s_type2",
1844
            array(
1845
                'type' => "admin",
1846
                'type2' => "settings"
1847
            )
1848
        );
1849
        foreach ($rows as $record) {
1850
            if ($record['type'] == 'admin') {
1851
                $SETTINGS[$record['intitule']] = $record['valeur'];
1852
            } else {
1853
                $settings[$record['intitule']] = $record['valeur'];
1854
            }
1855
        }
1856
        $SETTINGS['loaded'] = 1;
1857
        $SETTINGS['default_session_expiration_time'] = 5;
1858
    }
1859
}
1860
1861
/*
1862
** check if folder has custom fields.
1863
** Ensure that target one also has same custom fields
1864
*/
1865
function checkCFconsistency($source_id, $target_id)
1866
{
1867
    $source_cf = array();
1868
    $rows = DB::QUERY(
1869
        "SELECT id_category
1870
        FROM ".prefix_table("categories_folders")."
1871
        WHERE id_folder = %i",
1872
        $source_id
1873
    );
1874
    foreach ($rows as $record) {
1875
        array_push($source_cf, $record['id_category']);
1876
    }
1877
1878
    $target_cf = array();
1879
    $rows = DB::QUERY(
1880
        "SELECT id_category
1881
        FROM ".prefix_table("categories_folders")."
1882
        WHERE id_folder = %i",
1883
        $target_id
1884
    );
1885
    foreach ($rows as $record) {
1886
        array_push($target_cf, $record['id_category']);
1887
    }
1888
1889
    $cf_diff = array_diff($source_cf, $target_cf);
1890
    if (count($cf_diff) > 0) {
1891
        return false;
1892
    }
1893
1894
    return true;
1895
}
1896
1897
/*
1898
*
1899
*/
1900
function encrypt_or_decrypt_file($filename_to_rework, $filename_status)
1901
{
1902
    global $server, $user, $pass, $database, $port, $encoding;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1903
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
1904
1905
    // Include librairies & connect to DB
1906
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1907
    $pass = defuse_return_decrypted($pass);
1908
    DB::$host = $server;
1909
    DB::$user = $user;
1910
    DB::$password = $pass;
1911
    DB::$dbName = $database;
1912
    DB::$port = $port;
1913
    DB::$encoding = $encoding;
1914
    DB::$error_handler = true;
1915
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1916
    $link->set_charset($encoding);
1917
1918
    // Get file info in DB
1919
    $fileInfo = DB::queryfirstrow(
1920
        "SELECT id FROM ".prefix_table("files")." WHERE file = %s",
1921
        filter_var($filename_to_rework, FILTER_SANITIZE_STRING)
1922
    );
1923
    if (empty($fileInfo['id']) === false) {
1924
        // Load PhpEncryption library
1925
        $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
1926
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
1927
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
1928
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
1929
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
1930
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
1931
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
1932
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
1933
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
1934
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
1935
1936
        // Get KEY
1937
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
1938
1939
        if (isset($SETTINGS['enable_attachment_encryption'])
1940
            && $SETTINGS['enable_attachment_encryption'] === "1" &&
1941
            isset($filename_status)
1942
            && ($filename_status === "clear"
1943
                || $filename_status === "0")
1944
        ) {
1945
            // File needs to be encrypted
1946
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1947
                // Make a copy of file
1948
                if (!copy(
1949
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1950
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1951
                )) {
1952
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
1953
                } else {
1954
                    // Do a bck
1955
                    copy(
1956
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1957
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1958
                    );
1959
                }
1960
1961
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1962
1963
                // Now encrypt the file with saltkey
1964
                $err = '';
1965
                try {
1966
                    \Defuse\Crypto\File::encryptFile(
1967
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1968
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1969
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1970
                    );
1971
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1972
                    $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.";
1973
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1974
                    $err = $ex;
1975
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1976
                    $err = $ex;
1977
                }
1978
                if (empty($err) === false) {
1979
                    echo $err;
1980
                }
1981
1982
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1983
1984
                // update table
1985
                DB::update(
1986
                    prefix_table('files'),
1987
                    array(
1988
                        'status' => 'encrypted'
1989
                        ),
1990
                    "id = %i",
1991
                    $fileInfo['id']
1992
                );
1993
            }
1994
        } elseif (isset($SETTINGS['enable_attachment_encryption'])
1995
            && $SETTINGS['enable_attachment_encryption'] === "0"
1996
            && isset($filename_status)
1997
            && $filename_status === "encrypted"
1998
        ) {
1999
            // file needs to be decrypted
2000
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
2001
                // make a copy of file
2002
                if (!copy(
2003
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2004
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
2005
                )) {
2006
                    exit;
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

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

Loading history...
2007
                } else {
2008
                    // do a bck
2009
                    copy(
2010
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2011
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
2012
                    );
2013
                }
2014
2015
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
2016
2017
                // Now encrypt the file with saltkey
2018
                $err = '';
2019
                try {
2020
                    \Defuse\Crypto\File::decryptFile(
2021
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
2022
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2023
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2024
                    );
2025
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2026
                    $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.";
2027
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2028
                    $err = $ex;
2029
                } catch (Defuse\Crypto\Exception\IOException $ex) {
2030
                    $err = $ex;
2031
                }
2032
                if (empty($err) === false) {
2033
                    echo $err;
2034
                }
2035
2036
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
2037
2038
                // update table
2039
                DB::update(
2040
                    prefix_table('files'),
2041
                    array(
2042
                        'status' => 'clear'
2043
                        ),
2044
                    "id = %i",
2045
                    $fileInfo['id']
2046
                );
2047
            }
2048
        }
2049
    }
2050
2051
    // Exit
2052
    return false;
2053
}
2054
2055
/**
2056
 * Will encrypte/decrypt a fil eusing Defuse
2057
 * @param  string $type        can be either encrypt or decrypt
2058
 * @param  string $source_file path to source file
2059
 * @param  string $target_file path to target file
2060
 * @return string|boolean
2061
 */
2062
function prepareFileWithDefuse($type, $source_file, $target_file, $password = '')
2063
{
2064
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
2065
2066
    // Load AntiXSS
2067
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2068
    $antiXss = new protect\AntiXSS\AntiXSS();
2069
2070
    // Protect against bad inputs
2071
    if (is_array($source_file) || is_array($target_file)) {
0 ignored issues
show
introduced by
The condition is_array($target_file) is always false.
Loading history...
2072
        return 'error_cannot_be_array';
2073
    }
2074
2075
    // Sanitize
2076
    $source_file = $antiXss->xss_clean($source_file);
2077
    $target_file = $antiXss->xss_clean($target_file);
2078
2079
    // load PhpEncryption library
2080
    $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
2081
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
2082
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
2083
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
2084
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
2085
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
2086
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
2087
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
2088
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
2089
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
2090
2091
    if (empty($password) === true) {
2092
        /*
2093
        File encryption/decryption is done with the SALTKEY
2094
         */
2095
2096
        // get KEY
2097
        $ascii_key = file_get_contents(SECUREPATH."/teampass-seckey.txt");
0 ignored issues
show
Bug introduced by
The constant SECUREPATH was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
2098
2099
        // Now perform action on the file
2100
        $err = '';
2101
        if ($type === 'decrypt') {
2102
            try {
2103
                \Defuse\Crypto\File::decryptFile(
2104
                    $source_file,
2105
                    $target_file,
2106
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2107
                );
2108
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2109
                $err = "decryption_not_possible";
2110
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2111
                $err = $ex;
2112
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2113
                $err = $ex;
2114
            }
2115
        } elseif ($type === 'encrypt') {
2116
            try {
2117
                \Defuse\Crypto\File::encryptFile(
2118
                    $source_file,
2119
                    $target_file,
2120
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2121
                );
2122
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2123
                $err = "encryption_not_possible";
2124
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2125
                $err = $ex;
2126
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2127
                $err = $ex;
2128
            }
2129
        }
2130
    } else {
2131
        /*
2132
        File encryption/decryption is done with special password and not the SALTKEY
2133
         */
2134
2135
        $err = '';
2136
        if ($type === 'decrypt') {
2137
            try {
2138
                \Defuse\Crypto\File::decryptFileWithPassword(
2139
                    $source_file,
2140
                    $target_file,
2141
                    $password
2142
                );
2143
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2144
                $err = "wrong_key";
2145
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2146
                $err = $ex;
2147
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2148
                $err = $ex;
2149
            }
2150
        } elseif ($type === 'encrypt') {
2151
            try {
2152
                \Defuse\Crypto\File::encryptFileWithPassword(
2153
                    $source_file,
2154
                    $target_file,
2155
                    $password
2156
                );
2157
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2158
                $err = "wrong_key";
2159
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2160
                $err = $ex;
2161
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2162
                $err = $ex;
2163
            }
2164
        }
2165
    }
2166
2167
    // return error
2168
    if (empty($err) === false) {
2169
        return $err;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $err also could return the type Defuse\Crypto\Exception\...o\Exception\IOException which is incompatible with the documented return type string|boolean.
Loading history...
2170
    } else {
2171
        return true;
2172
    }
2173
}
2174
2175
/*
2176
* NOT TO BE USED
2177
*/
2178
function debugTeampass($text)
2179
{
2180
    $debugFile = fopen('D:/wamp64/www/TeamPass/debug.txt', 'r+');
2181
    fputs($debugFile, $text);
0 ignored issues
show
Bug introduced by
It seems like $debugFile can also be of type false; however, parameter $handle of fputs() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2181
    fputs(/** @scrutinizer ignore-type */ $debugFile, $text);
Loading history...
2182
    fclose($debugFile);
0 ignored issues
show
Bug introduced by
It seems like $debugFile can also be of type false; however, parameter $handle of fclose() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2182
    fclose(/** @scrutinizer ignore-type */ $debugFile);
Loading history...
2183
}
2184
2185
2186
/**
2187
 * DELETE the file with expected command depending on server type
2188
 * @param  string $file Path to file
2189
 * @return              Nothing
0 ignored issues
show
Bug introduced by
The type Nothing was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
2190
 */
2191
function fileDelete($file)
2192
{
2193
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
2194
2195
    // Load AntiXSS
2196
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2197
    $antiXss = new protect\AntiXSS\AntiXSS();
2198
2199
    $file = $antiXss->xss_clean($file);
2200
    if (is_file($file)) {
2201
        unlink($file);
2202
    }
2203
}
2204
2205
/**
2206
 * Permits to extract the file extension
2207
 *
2208
 * @param  string $file File name
2209
 * @return string
2210
 */
2211
function getFileExtension(string $file)
2212
{
2213
    if (strpos($file, '.') === false) {
2214
        return $file;
2215
    }
2216
2217
    return substr($file, strrpos($file, '.') + 1);
2218
}
2219
2220
/**
2221
 * Permits to clean and sanitize text to be displayed
2222
 * @param  string $text Text to clean
2223
 * @param  string $type What clean to perform
2224
 * @return string
2225
 */
2226
function cleanText(string $string, string $type = "")
2227
{
2228
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
2229
2230
    // Load AntiXSS
2231
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2232
    $antiXss = new protect\AntiXSS\AntiXSS();
2233
2234
    if ($type === "css") {
2235
        // Escape text and quotes in UTF8 format
2236
        return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2237
    } elseif ($type === "html" || empty($type)) {
2238
        // Html cleaner
2239
        return $antiXss->xss_clean($string);
2240
    }
2241
}
2242
2243
/**
2244
 * Performs chmod operation on subfolders
2245
 * @param  string  $dir             Parent folder
2246
 * @param  integer $dirPermissions  New permission on folders
2247
 * @param  integer $filePermissions New permission on files
2248
 * @return boolean
2249
 */
2250
function chmodRecursive($dir, $dirPermissions, $filePermissions)
2251
{
2252
    $pointer_dir = opendir($dir);
2253
    $res = true;
2254
    while ($file = readdir($pointer_dir)) {
0 ignored issues
show
Bug introduced by
It seems like $pointer_dir can also be of type false; however, parameter $dir_handle of readdir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2254
    while ($file = readdir(/** @scrutinizer ignore-type */ $pointer_dir)) {
Loading history...
2255
        if (($file == ".") || ($file == "..")) {
2256
            continue;
2257
        }
2258
2259
        $fullPath = $dir."/".$file;
2260
2261
        if (is_dir($fullPath)) {
2262
            if ($res = @chmod($fullPath, $dirPermissions)) {
2263
                $res = @chmodRecursive($fullPath, $dirPermissions, $filePermissions);
2264
            }
2265
        } else {
2266
            $res = chmod($fullPath, $filePermissions);
2267
        }
2268
        if (!$res) {
2269
            closedir($pointer_dir);
0 ignored issues
show
Bug introduced by
It seems like $pointer_dir can also be of type false; however, parameter $dir_handle of closedir() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2269
            closedir(/** @scrutinizer ignore-type */ $pointer_dir);
Loading history...
2270
            return false;
2271
        }
2272
    }
2273
    closedir($pointer_dir);
2274
    if (is_dir($dir) && $res) {
2275
        $res = @chmod($dir, $dirPermissions);
2276
    }
2277
2278
    return $res;
2279
}
2280
2281
/**
2282
 * Check if user can access to this item
2283
 * @param integer $item_id ID of item
2284
 */
2285
function accessToItemIsGranted($item_id)
2286
{
2287
    global $SETTINGS;
0 ignored issues
show
Compatibility Best Practice introduced by
Use of global functionality is not recommended; it makes your code harder to test, and less reusable.

Instead of relying on global state, we recommend one of these alternatives:

1. Pass all data via parameters

function myFunction($a, $b) {
    // Do something
}

2. Create a class that maintains your state

class MyClass {
    private $a;
    private $b;

    public function __construct($a, $b) {
        $this->a = $a;
        $this->b = $b;
    }

    public function myFunction() {
        // Do something
    }
}
Loading history...
2288
2289
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2290
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2291
2292
    // Prepare superGlobal variables
2293
    $session_groupes_visibles = $superGlobal->get("groupes_visibles", "SESSION");
2294
    $session_list_restricted_folders_for_items = $superGlobal->get("list_restricted_folders_for_items", "SESSION");
2295
2296
    // Load item data
2297
    $data = DB::queryFirstRow(
2298
        "SELECT id_tree
2299
        FROM ".prefix_table("items")."
2300
        WHERE id = %i",
2301
        $item_id
2302
    );
2303
2304
    // Check if user can access this folder
2305
    if (in_array($data['id_tree'], $session_groupes_visibles) === false) {
2306
        // Now check if this folder is restricted to user
2307
        if (isset($session_list_restricted_folders_for_items[$data['id_tree']])
2308
            && !in_array($item_id, $session_list_restricted_folders_for_items[$data['id_tree']])
2309
        ) {
2310
            return "ERR_FOLDER_NOT_ALLOWED";
2311
        } else {
2312
            return "ERR_FOLDER_NOT_ALLOWED";
2313
        }
2314
    }
2315
2316
    return true;
2317
}
2318
2319
/**
2320
 * Creates a unique key
2321
 * @lenght  integer $lenght Key lenght
2322
 * @return string
2323
 */
2324
function uniqidReal($lenght = 13)
2325
{
2326
    // uniqid gives 13 chars, but you could adjust it to your needs.
2327
    if (function_exists("random_bytes")) {
2328
        $bytes = random_bytes(ceil($lenght / 2));
0 ignored issues
show
Bug introduced by
ceil($lenght / 2) of type double is incompatible with the type integer expected by parameter $length of random_bytes(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2328
        $bytes = random_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2329
    } elseif (function_exists("openssl_random_pseudo_bytes")) {
2330
        $bytes = openssl_random_pseudo_bytes(ceil($lenght / 2));
0 ignored issues
show
Bug introduced by
ceil($lenght / 2) of type double is incompatible with the type integer expected by parameter $length of openssl_random_pseudo_bytes(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

2330
        $bytes = openssl_random_pseudo_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2331
    } else {
2332
        throw new Exception("no cryptographically secure random function available");
2333
    }
2334
    return substr(bin2hex($bytes), 0, $lenght);
2335
}
2336
2337
/**
2338
 * Obfuscate an email address
2339
 * @email {string}  email address
2340
 */
2341
function obfuscate_email($email)
2342
{
2343
    $prop = 2;
2344
    $start = '';
2345
    $end = '';
2346
    $domain = substr(strrchr($email, "@"), 1);
2347
    $mailname = str_replace($domain, '', $email);
2348
    $name_l = strlen($mailname);
2349
    $domain_l = strlen($domain);
2350
    for ($i = 0; $i <= $name_l / $prop - 1; $i++) {
2351
        $start .= 'x';
2352
    }
2353
2354
    for ($i = 0; $i <= $domain_l / $prop - 1; $i++) {
2355
        $end .= 'x';
2356
    }
2357
2358
    return substr_replace($mailname, $start, 2, $name_l / $prop)
2359
        .substr_replace($domain, $end, 2, $domain_l / $prop);
2360
}
2361
2362
/**
2363
 * Permits to get LDAP information about a user
2364
 *
2365
 * @param string $username  User name
2366
 * @param string $password  User password
2367
 * @return string
2368
 */
2369
function connectLDAP($username, $password, $SETTINGS)
2370
{
2371
    $user_email = '';
2372
    $user_found = false;
2373
    $user_lastname = '';
2374
    $user_name = '';
2375
    $ldapConnection = false;
2376
2377
    // Prepare LDAP connection if set up
2378
    //Multiple Domain Names
2379
    if (strpos(html_entity_decode($username), '\\') === true) {
2380
        $ldap_suffix = "@".substr(html_entity_decode($username), 0, strpos(html_entity_decode($username), '\\'));
0 ignored issues
show
Unused Code introduced by
The assignment to $ldap_suffix is dead and can be removed.
Loading history...
2381
        $username = substr(html_entity_decode($username), strpos(html_entity_decode($username), '\\') + 1);
2382
    }
2383
    if ($SETTINGS['ldap_type'] === 'posix-search') {
2384
        $ldapURIs = "";
2385
        foreach (explode(",", $SETTINGS['ldap_domain_controler']) as $domainControler) {
2386
            if ($SETTINGS['ldap_ssl'] == 1) {
2387
                $ldapURIs .= "ldaps://".$domainControler.":".$SETTINGS['ldap_port']." ";
2388
            } else {
2389
                $ldapURIs .= "ldap://".$domainControler.":".$SETTINGS['ldap_port']." ";
2390
            }
2391
        }
2392
        $ldapconn = ldap_connect($ldapURIs);
2393
2394
        if ($SETTINGS['ldap_tls']) {
2395
            ldap_start_tls($ldapconn);
2396
        }
2397
        ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
2398
        ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
2399
2400
        // Is LDAP connection ready?
2401
        if ($ldapconn !== false) {
2402
            // Should we bind the connection?
2403
            if ($SETTINGS['ldap_bind_dn'] !== "" && $SETTINGS['ldap_bind_passwd'] !== "") {
2404
                $ldapbind = ldap_bind($ldapconn, $SETTINGS['ldap_bind_dn'], $SETTINGS['ldap_bind_passwd']);
2405
            } else {
2406
                $ldapbind = false;
2407
            }
2408
            if (($SETTINGS['ldap_bind_dn'] === "" && $SETTINGS['ldap_bind_passwd'] === "") || $ldapbind === true) {
2409
                $filter = "(&(".$SETTINGS['ldap_user_attribute']."=".$username.")(objectClass=".$SETTINGS['ldap_object_class']."))";
2410
                $result = ldap_search(
2411
                    $ldapconn,
2412
                    $SETTINGS['ldap_search_base'],
2413
                    $filter,
2414
                    array('dn', 'mail', 'givenname', 'sn', 'samaccountname')
2415
                );
2416
2417
                // Check if user was found in AD
2418
                if (ldap_count_entries($ldapconn, $result) > 0) {
2419
                    // Get user's info and especially the DN
2420
                    $result = ldap_get_entries($ldapconn, $result);
2421
                    $user_dn = $result[0]['dn'];
2422
                    $user_email = $result[0]['mail'][0];
2423
                    $user_lastname = $result[0]['sn'][0];
2424
                    $user_name = isset($result[0]['givenname'][0]) === true ? $result[0]['givenname'][0] : '';
2425
                    $user_found = true;
2426
2427
                    // Should we restrain the search in specified user groups
2428
                    $GroupRestrictionEnabled = false;
2429
                    if (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === false) {
2430
                        // New way to check User's group membership
2431
                        $filter_group = "memberUid=".$username;
2432
                        $result_group = ldap_search(
2433
                            $ldapconn,
2434
                            $SETTINGS['ldap_search_base'],
2435
                            $filter_group,
2436
                            array('dn', 'samaccountname')
2437
                        );
2438
2439
                        if ($result_group) {
0 ignored issues
show
introduced by
$result_group is of type resource, thus it always evaluated to false.
Loading history...
2440
                            $entries = ldap_get_entries($ldapconn, $result_group);
2441
2442
                            if ($entries['count'] > 0) {
2443
                                // Now check if group fits
2444
                                for ($i = 0; $i < $entries['count']; $i++) {
2445
                                    $parsr = ldap_explode_dn($entries[$i]['dn'], 0);
2446
                                    if (str_replace(array('CN=', 'cn='), '', $parsr[0]) === $SETTINGS['ldap_usergroup']) {
2447
                                        $GroupRestrictionEnabled = true;
2448
                                        break;
2449
                                    }
2450
                                }
2451
                            }
2452
                        }
2453
                    }
2454
2455
                    // Is user in the LDAP?
2456
                    if ($GroupRestrictionEnabled === true
2457
                        || (
2458
                            $GroupRestrictionEnabled === false
2459
                            && (
2460
                                isset($SETTINGS['ldap_usergroup']) === false
2461
                                || (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === true)
2462
                            )
2463
                        )
2464
                    ) {
2465
                        // Try to auth inside LDAP
2466
                        $ldapbind = ldap_bind($ldapconn, $user_dn, $password);
2467
                        if ($ldapbind === true) {
2468
                            $ldapConnection = true;
2469
                        } else {
2470
                            $ldapConnection = false;
2471
                        }
2472
                    }
2473
                } else {
2474
                    $ldapConnection = false;
2475
                }
2476
            } else {
2477
                $ldapConnection = false;
2478
            }
2479
        } else {
2480
            $ldapConnection = false;
2481
        }
2482
    } else {
2483
        $adldap = new SplClassLoader('adLDAP', '../includes/libraries/LDAP');
2484
        $adldap->register();
2485
2486
        // Posix style LDAP handles user searches a bit differently
2487
        if ($SETTINGS['ldap_type'] === 'posix') {
2488
            $ldap_suffix = ','.$SETTINGS['ldap_suffix'].','.$SETTINGS['ldap_domain_dn'];
2489
        } else {
2490
            // case where $SETTINGS['ldap_type'] equals 'windows'
0 ignored issues
show
Unused Code Comprehensibility introduced by
47% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
2491
            //Multiple Domain Names
2492
            $ldap_suffix = $SETTINGS['ldap_suffix'];
2493
        }
2494
2495
        // Ensure no double commas exist in ldap_suffix
2496
        $ldap_suffix = str_replace(',,', ',', $ldap_suffix);
2497
2498
        // Create LDAP connection
2499
        $adldap = new adLDAP\adLDAP(
2500
            array(
2501
                'base_dn' => $SETTINGS['ldap_domain_dn'],
2502
                'account_suffix' => $ldap_suffix,
2503
                'domain_controllers' => explode(",", $SETTINGS['ldap_domain_controler']),
2504
                'ad_port' => $SETTINGS['ldap_port'],
2505
                'use_ssl' => $SETTINGS['ldap_ssl'],
2506
                'use_tls' => $SETTINGS['ldap_tls']
2507
            )
2508
        );
2509
2510
        // OpenLDAP expects an attribute=value pair
2511
        if ($SETTINGS['ldap_type'] === 'posix') {
2512
            $auth_username = $SETTINGS['ldap_user_attribute'].'='.$username;
2513
        } else {
2514
            $auth_username = $username;
2515
        }
2516
2517
        // Authenticate the user
2518
        if ($adldap->authenticate($auth_username, html_entity_decode($password))) {
2519
            // Get user info
2520
            $result = $adldap->user()->info($auth_username, array('mail', 'givenname', 'sn'));
2521
            $user_email = $result[0]['mail'][0];
2522
            $user_lastname = $result[0]['sn'][0];
2523
            $user_name = $result[0]['givenname'][0];
2524
            $user_found = true;
2525
2526
            // Is user in allowed group
2527
            if (isset($SETTINGS['ldap_allowed_usergroup']) === true
2528
                && empty($SETTINGS['ldap_allowed_usergroup']) === false
2529
            ) {
2530
                if ($adldap->user()->inGroup($auth_username, $SETTINGS['ldap_allowed_usergroup']) === true) {
2531
                    $ldapConnection = true;
2532
                } else {
2533
                    $ldapConnection = false;
2534
                }
2535
            } else {
2536
                $ldapConnection = true;
2537
            }
2538
        } else {
2539
            $ldapConnection = false;
2540
        }
2541
    }
2542
2543
    return json_encode(
2544
        array(
2545
            'lastname' => $user_lastname,
2546
            'name' => $user_name,
2547
            'email' => $user_email,
2548
            'auth_success' => $ldapConnection,
2549
            'user_found' => $user_found
2550
        )
2551
    );
2552
}
2553