Passed
Push — development ( 6ad9b0...92a808 )
by Nils
05:10
created

logItems()   D

Complexity

Conditions 9
Paths 9

Size

Total Lines 100
Code Lines 60

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 9
eloc 60
c 4
b 0
f 0
nc 9
nop 8
dl 0
loc 100
rs 4.8196

How to fix   Long Method    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

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 14 and the first side effect is on line 17.

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

100
                /** @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...
101
                    MCRYPT_RIJNDAEL_256,
102
                    $personalSalt,
103
                    $text,
104
                    MCRYPT_MODE_ECB,
105
                    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

105
                    /** @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...
106
                        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

106
                        /** @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...
107
                        MCRYPT_RAND
108
                    )
109
                )
110
            )
111
        );
112
    }
113
114
    // If $personalSalt is not empty
115
    return trim(
116
        base64_encode(
117
            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

117
            /** @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...
118
                MCRYPT_RIJNDAEL_256,
119
                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...
120
                $text,
121
                MCRYPT_MODE_ECB,
122
                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

122
                /** @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...
123
                    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

123
                    /** @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...
124
                    MCRYPT_RAND
125
                )
126
            )
127
        )
128
    );
129
}
130
131
/**
132
 * decryptOld()
133
 *
134
 * decrypt a crypted string
135
 */
136
function decryptOld($text, $personalSalt = "")
137
{
138
    if (!empty($personalSalt)) {
139
        return trim(
140
            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

140
            /** @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...
141
                MCRYPT_RIJNDAEL_256,
142
                $personalSalt,
143
                base64_decode($text),
144
                MCRYPT_MODE_ECB,
145
                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

145
                /** @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...
146
                    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

146
                    /** @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...
147
                    MCRYPT_RAND
148
                )
149
            )
150
        );
151
    }
152
153
    // No personal SK
154
    return trim(
155
        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

155
        /** @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...
156
            MCRYPT_RIJNDAEL_256,
157
            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...
158
            base64_decode($text),
159
            MCRYPT_MODE_ECB,
160
            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

160
            /** @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...
161
                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

161
                /** @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...
162
                MCRYPT_RAND
163
            )
164
        )
165
    );
166
}
167
168
/**
169
 * encrypt()
170
 *
171
 * crypt a string
172
 * @param string $decrypted
173
 */
174
function encrypt($decrypted, $personalSalt = "")
175
{
176
    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...
177
178
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
179
        require_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
180
    } else {
181
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
182
    }
183
184
    if (!empty($personalSalt)) {
185
        $staticSalt = $personalSalt;
186
    } else {
187
        $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...
188
    }
189
190
    //set our salt to a variable
191
    // Get 64 random bits for the salt for pbkdf2
192
    $pbkdf2Salt = getBits(64);
193
    // generate a pbkdf2 key to use for the encryption.
194
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
195
    // Build $init_vect and $ivBase64.  We use a block size of 256 bits (AES compliant)
196
    // and CTR mode.  (Note: ECB mode is inadequate as IV is not used.)
197
    $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

197
    $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

197
    $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...
198
199
    //base64 trim
200
    if (strlen($ivBase64 = rtrim(base64_encode($init_vect), '=')) != 43) {
201
        return false;
202
    }
203
    // Encrypt $decrypted
204
    $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

204
    $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...
205
    // MAC the encrypted text
206
    $mac = hash_hmac('sha256', $encrypted, $staticSalt);
207
    // We're done!
208
    return base64_encode($ivBase64.$encrypted.$mac.$pbkdf2Salt);
209
}
210
211
/**
212
 * decrypt()
213
 *
214
 * decrypt a crypted string
215
 */
216
function decrypt($encrypted, $personalSalt = "")
217
{
218
    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...
219
220
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
221
        include_once '../includes/libraries/Encryption/PBKDF2/PasswordHash.php';
222
    } else {
223
        include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/PBKDF2/PasswordHash.php';
224
    }
225
226
    if (!empty($personalSalt)) {
227
        $staticSalt = $personalSalt;
228
    } else {
229
        $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...
230
    }
231
    //base64 decode the entire payload
232
    $encrypted = base64_decode($encrypted);
233
    // get the salt
234
    $pbkdf2Salt = substr($encrypted, -64);
235
    //remove the salt from the string
236
    $encrypted = substr($encrypted, 0, -64);
237
    $key = substr(pbkdf2('sha256', $staticSalt, $pbkdf2Salt, ITCOUNT, 16 + 32, true), 32, 16);
238
    // Retrieve $init_vect which is the first 22 characters plus ==, base64_decoded.
239
    $init_vect = base64_decode(substr($encrypted, 0, 43).'==');
240
    // Remove $init_vect from $encrypted.
241
    $encrypted = substr($encrypted, 43);
242
    // Retrieve $mac which is the last 64 characters of $encrypted.
243
    $mac = substr($encrypted, -64);
244
    // Remove the last 64 chars from encrypted (remove MAC)
245
    $encrypted = substr($encrypted, 0, -64);
246
    //verify the sha256hmac from the encrypted data before even trying to decrypt it
247
    if (hash_hmac('sha256', $encrypted, $staticSalt) != $mac) {
248
        return false;
249
    }
250
    // Decrypt the data.
251
    $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

251
    $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...
252
    // Yay!
253
    return $decrypted;
254
}
255
256
257
/**
258
 * genHash()
259
 *
260
 * Generate a hash for user login
261
 * @param string $password
262
 */
263
function bCrypt($password, $cost)
264
{
265
    $salt = sprintf('$2y$%02d$', $cost);
266
    if (function_exists('openssl_random_pseudo_bytes')) {
267
        $salt .= bin2hex(openssl_random_pseudo_bytes(11));
268
    } else {
269
        $chars = './ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
270
        for ($i = 0; $i < 22; $i++) {
271
            $salt .= $chars[mt_rand(0, 63)];
272
        }
273
    }
274
    return crypt($password, $salt);
275
}
276
277
function cryption_before_defuse($message, $saltkey, $init_vect, $type = null, $scope = "public")
278
{
279
    if (DEFUSE_ENCRYPTION === true) {
0 ignored issues
show
introduced by
The condition DEFUSE_ENCRYPTION === true is always true.
Loading history...
280
        if ($scope === "perso") {
281
            return defuse_crypto(
0 ignored issues
show
Bug introduced by
The function defuse_crypto was not found. Maybe you did not declare it correctly or list all dependencies? ( Ignorable by Annotation )

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

281
            return /** @scrutinizer ignore-call */ defuse_crypto(
Loading history...
282
                $message,
283
                $saltkey,
284
                $type
285
            );
286
        } else {
287
            return defuse_crypto(
288
                $message,
289
                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...
290
                $type
291
            );
292
        }
293
    } else {
294
        return cryption_phpCrypt($message, $saltkey, $init_vect, $type);
295
    }
296
}
297
298
/*
299
 * cryption() - Encrypt and decrypt string based upon phpCrypt library
300
 *
301
 * Using AES_128 and mode CBC
302
 *
303
 * $key and $init_vect have to be given in hex format
304
 */
305
function cryption_phpCrypt($string, $key, $init_vect, $type)
306
{
307
    // manage key origin
308
    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...
309
        // check key (AES-128 requires a 16 bytes length key)
310
        if (strlen($key) < 16) {
311
            for ($inc = strlen($key) + 1; $inc <= 16; $inc++) {
312
                $key .= chr(0);
313
            }
314
        } elseif (strlen($key) > 16) {
315
            $key = substr($key, 16);
316
        }
317
    }
318
319
    // load crypt
320
    $crypt = new PHP_Crypt($key, PHP_Crypt::CIPHER_AES_128, PHP_Crypt::MODE_CBC);
321
322
    if ($type == "encrypt") {
323
        // generate IV and encrypt
324
        $init_vect = $crypt->createIV();
325
        $encrypt = $crypt->encrypt($string);
326
        // return
327
        return array(
328
            "string" => bin2hex($encrypt),
329
            "iv" => bin2hex($init_vect),
330
            "error" => empty($encrypt) ? "ERR_ENCRYPTION_NOT_CORRECT" : ""
331
        );
332
    } elseif ($type == "decrypt") {
333
        // case if IV is empty
334
        if (empty($init_vect)) {
335
                    return array(
336
                'string' => "",
337
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
338
            );
339
        }
340
341
        // convert
342
        try {
343
            $string = testHex2Bin(trim($string));
344
            $init_vect = testHex2Bin($init_vect);
345
        } catch (Exception $e) {
346
            return array(
347
                'string' => "",
348
                'error' => "ERR_ENCRYPTION_NOT_CORRECT"
349
            );
350
        }
351
352
        // load IV
353
        $crypt->IV($init_vect);
354
        // decrypt
355
        $decrypt = $crypt->decrypt($string);
356
        // return
357
        return array(
358
            'string' => str_replace(chr(0), "", $decrypt),
359
            'error' => ""
360
        );
361
    }
362
}
363
364
function testHex2Bin($val)
365
{
366
    if (!@hex2bin($val)) {
367
        throw new Exception("ERROR");
368
    }
369
    return hex2bin($val);
370
}
371
372
/**
373
 * @param string $ascii_key
374
 * @param string $type
375
 */
376
function cryption($message, $ascii_key, $type) //defuse_crypto
377
{
378
    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...
379
380
    // load PhpEncryption library
381
    if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir'])) {
382
        $path = '../includes/libraries/Encryption/Encryption/';
383
    } else {
384
        $path = $SETTINGS['cpassman_dir'].'/includes/libraries/Encryption/Encryption/';
385
    }
386
387
    include_once $path.'Crypto.php';
388
    include_once $path.'Encoding.php';
389
    include_once $path.'DerivedKeys.php';
390
    include_once $path.'Key.php';
391
    include_once $path.'KeyOrPassword.php';
392
    include_once $path.'File.php';
393
    include_once $path.'RuntimeTests.php';
394
    include_once $path.'KeyProtectedByPassword.php';
395
    include_once $path.'Core.php';
396
397
    // init
398
    $err = '';
399
    if (empty($ascii_key) === true) {
400
        $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...
401
    }
402
403
    // convert KEY
404
    $key = \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key);
405
406
    try {
407
        if ($type === "encrypt") {
408
            $text = \Defuse\Crypto\Crypto::encrypt($message, $key);
409
        } elseif ($type === "decrypt") {
410
            $text = \Defuse\Crypto\Crypto::decrypt($message, $key);
411
        }
412
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
413
        $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.";
414
    } catch (Defuse\Crypto\Exception\BadFormatException $ex) {
415
        $err = $ex;
416
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
417
        $err = $ex;
418
    } catch (Defuse\Crypto\Exception\CryptoException $ex) {
419
        $err = $ex;
420
    } catch (Defuse\Crypto\Exception\IOException $ex) {
421
        $err = $ex;
422
    }
423
424
    return array(
425
        'string' => isset($text) ? $text : "",
426
        'error' => $err
427
    );
428
}
429
430
function defuse_generate_key()
431
{
432
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
433
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
434
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
435
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
436
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
437
    require_once '../includes/libraries/Encryption/Encryption/File.php';
438
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
439
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
440
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
441
442
    $key = \Defuse\Crypto\Key::createNewRandomKey();
443
    $key = $key->saveToAsciiSafeString();
444
    return $key;
445
}
446
447
function defuse_generate_personal_key($psk)
448
{
449
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
450
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
451
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
452
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
453
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
454
    require_once '../includes/libraries/Encryption/Encryption/File.php';
455
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
456
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
457
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
458
459
    $protected_key = \Defuse\Crypto\KeyProtectedByPassword::createRandomPasswordProtectedKey($psk);
460
    $protected_key_encoded = $protected_key->saveToAsciiSafeString();
461
462
    return $protected_key_encoded; // save this in user table
463
}
464
465
/**
466
 * @param string $psk
467
 */
468
function defuse_validate_personal_key($psk, $protected_key_encoded)
469
{
470
    require_once '../includes/libraries/Encryption/Encryption/Crypto.php';
471
    require_once '../includes/libraries/Encryption/Encryption/Encoding.php';
472
    require_once '../includes/libraries/Encryption/Encryption/DerivedKeys.php';
473
    require_once '../includes/libraries/Encryption/Encryption/Key.php';
474
    require_once '../includes/libraries/Encryption/Encryption/KeyOrPassword.php';
475
    require_once '../includes/libraries/Encryption/Encryption/File.php';
476
    require_once '../includes/libraries/Encryption/Encryption/RuntimeTests.php';
477
    require_once '../includes/libraries/Encryption/Encryption/KeyProtectedByPassword.php';
478
    require_once '../includes/libraries/Encryption/Encryption/Core.php';
479
480
    try {
481
        $protected_key = \Defuse\Crypto\KeyProtectedByPassword::loadFromAsciiSafeString($protected_key_encoded);
482
        $user_key = $protected_key->unlockKey($psk);
483
        $user_key_encoded = $user_key->saveToAsciiSafeString();
484
    } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
485
        return "Error - Major issue as the encryption is broken.";
486
    } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
487
        return "Error - The saltkey is not the correct one.";
488
    }
489
490
    return $user_key_encoded; // store it in session once user has entered his psk
491
}
492
493
/**
494
 * Decrypt a defuse string if encrypted
495
 * @param  [type] $value Encrypted string
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
496
 * @return [type]        Decrypted string
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
497
 */
498
function defuse_return_decrypted($value)
499
{
500
    if (substr($value, 0, 3) === "def") {
501
        $value = cryption($value, "", "decrypt")['string'];
502
    }
503
    return $value;
504
}
505
506
/**
507
 * trimElement()
508
 *
509
 * trim a string depending on a specific string
510
 * @param string $element
511
 * @return string
512
 */
513
function trimElement($chaine, $element)
514
{
515
    if (!empty($chaine)) {
516
        if (is_array($chaine) === true) {
517
            $chaine = implode(";", $chaine);
518
        }
519
        $chaine = trim($chaine);
520
        if (substr($chaine, 0, 1) == $element) {
521
            $chaine = substr($chaine, 1);
522
        }
523
        if (substr($chaine, strlen($chaine) - 1, 1) == $element) {
524
            $chaine = substr($chaine, 0, strlen($chaine) - 1);
525
        }
526
    }
527
    return $chaine;
528
}
529
530
/**
531
 * cleanString()
532
 *
533
 * permits to suppress all "special" characters from string
534
 */
535
function cleanString($string, $special = false)
536
{
537
    // Create temporary table for special characters escape
538
    $tabSpecialChar = array();
539
    for ($i = 0; $i <= 31; $i++) {
540
        $tabSpecialChar[] = chr($i);
541
    }
542
    array_push($tabSpecialChar, "<br />");
543
    if ($special == "1") {
544
        $tabSpecialChar = array_merge($tabSpecialChar, array("</li>", "<ul>", "<ol>"));
545
    }
546
547
    return str_replace($tabSpecialChar, "\n", $string);
548
}
549
550
function db_error_handler($params)
551
{
552
    echo "Error: ".$params['error']."<br>\n";
553
    echo "Query: ".$params['query']."<br>\n";
554
    throw new Exception("Error - Query", 1);
555
}
556
557
/**
558
 * [identifyUserRights description]
559
 * @param  string $groupesVisiblesUser  [description]
560
 * @param  string $groupesInterditsUser [description]
561
 * @param  string $isAdmin              [description]
562
 * @param  string $idFonctions          [description]
563
 * @return string                       [description]
564
 */
565
function identifyUserRights(
566
    $groupesVisiblesUser,
567
    $groupesInterditsUser,
568
    $isAdmin,
569
    $idFonctions,
570
    $server,
571
    $user,
572
    $pass,
573
    $database,
574
    $port,
575
    $encoding,
576
    $SETTINGS
577
) {
578
    //load ClassLoader
579
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
580
581
    //Connect to DB
582
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
583
    $pass = defuse_return_decrypted($pass);
584
    DB::$host = $server;
585
    DB::$user = $user;
586
    DB::$password = $pass;
587
    DB::$dbName = $database;
588
    DB::$port = $port;
589
    DB::$encoding = $encoding;
590
    DB::$error_handler = true;
591
    $link = mysqli_connect($server, $user, $pass, $database, $port);
592
    $link->set_charset($encoding);
593
594
    //Build tree
595
    $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
596
    $tree->register();
597
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
598
599
    // Check if user is ADMINISTRATOR
600
    if ($isAdmin === '1') {
601
        $groupesVisibles = array();
602
        $_SESSION['personal_folders'] = array();
603
        $_SESSION['groupes_visibles'] = array();
604
        $_SESSION['groupes_interdits'] = array();
605
        $_SESSION['personal_visible_groups'] = array();
606
        $_SESSION['read_only_folders'] = array();
607
        $_SESSION['list_restricted_folders_for_items'] = array();
608
        $_SESSION['list_folders_editable_by_role'] = array();
609
        $_SESSION['list_folders_limited'] = array();
610
        $_SESSION['no_access_folders'] = array();
611
        $_SESSION['groupes_visibles_list'] = "";
612
        $rows = DB::query("SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i", 0);
613
        foreach ($rows as $record) {
614
            array_push($groupesVisibles, $record['id']);
615
        }
616
        $_SESSION['groupes_visibles'] = $groupesVisibles;
617
        $_SESSION['all_non_personal_folders'] = $groupesVisibles;
618
        // Exclude all PF
619
        $_SESSION['forbiden_pfs'] = array();
620
        $where = new WhereClause('and'); // create a WHERE statement of pieces joined by ANDs
621
        $where->add('personal_folder=%i', 1);
622
        if (isset($SETTINGS['enable_pf_feature']) && $SETTINGS['enable_pf_feature'] == 1) {
623
            $where->add('title=%s', $_SESSION['user_id']);
624
            $where->negateLast();
625
        }
626
        // Get ID of personal folder
627
        $persfld = DB::queryfirstrow(
628
            "SELECT id FROM ".prefix_table("nested_tree")." WHERE title = %s",
629
            $_SESSION['user_id']
630
        );
631
        if (!empty($persfld['id'])) {
632
            if (!in_array($persfld['id'], $_SESSION['groupes_visibles'])) {
633
                array_push($_SESSION['groupes_visibles'], $persfld['id']);
634
                array_push($_SESSION['personal_visible_groups'], $persfld['id']);
635
                // get all descendants
636
                $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
637
                $tree->rebuild();
638
                $tst = $tree->getDescendants($persfld['id']);
639
                foreach ($tst as $t) {
640
                    array_push($_SESSION['groupes_visibles'], $t->id);
641
                    array_push($_SESSION['personal_visible_groups'], $t->id);
642
                }
643
            }
644
        }
645
646
        // get complete list of ROLES
647
        $tmp = explode(";", $idFonctions);
648
        $rows = DB::query(
649
            "SELECT * FROM ".prefix_table("roles_title")."
650
            ORDER BY title ASC"
651
        );
652
        foreach ($rows as $record) {
653
            if (!empty($record['id']) && !in_array($record['id'], $tmp)) {
654
                array_push($tmp, $record['id']);
655
            }
656
        }
657
        $_SESSION['fonction_id'] = implode(";", $tmp);
658
659
        $_SESSION['groupes_visibles_list'] = implode(',', $_SESSION['groupes_visibles']);
660
        $_SESSION['is_admin'] = $isAdmin;
661
        // Check if admin has created Folders and Roles
662
        DB::query("SELECT * FROM ".prefix_table("nested_tree")."");
663
        $_SESSION['nb_folders'] = DB::count();
664
        DB::query("SELECT * FROM ".prefix_table("roles_title"));
665
        $_SESSION['nb_roles'] = DB::count();
666
    } else {
667
        // init
668
        $_SESSION['groupes_visibles'] = array();
669
        $_SESSION['personal_folders'] = array();
670
        $_SESSION['groupes_interdits'] = array();
671
        $_SESSION['personal_visible_groups'] = array();
672
        $_SESSION['read_only_folders'] = array();
673
        $_SESSION['fonction_id'] = $idFonctions;
674
        $groupesInterdits = array();
675
        if (is_array($groupesInterditsUser) === false) {
0 ignored issues
show
introduced by
The condition is_array($groupesInterditsUser) === false is always true.
Loading history...
676
            $groupesInterditsUser = explode(';', trimElement($groupesInterditsUser, ";"));
677
        }
678
        if (!empty($groupesInterditsUser) && count($groupesInterditsUser) > 0) {
679
            $groupesInterdits = $groupesInterditsUser;
680
        }
681
        $_SESSION['is_admin'] = $isAdmin;
682
        $fonctionsAssociees = explode(';', trimElement($idFonctions, ";"));
683
684
        $listAllowedFolders = $listFoldersLimited = $listFoldersEditableByRole = $listRestrictedFoldersForItems = $listReadOnlyFolders = array();
685
686
        // rechercher tous les groupes visibles en fonction des roles de l'utilisateur
687
        foreach ($fonctionsAssociees as $roleId) {
688
            if (empty($roleId) === false) {
689
                // Get allowed folders for each Role
690
                $rows = DB::query(
691
                    "SELECT folder_id FROM ".prefix_table("roles_values")." WHERE role_id=%i",
692
                    $roleId
693
                );
694
695
                if (DB::count() > 0) {
696
                    $tmp = DB::queryfirstrow(
697
                        "SELECT allow_pw_change FROM ".prefix_table("roles_title")." WHERE id = %i",
698
                        $roleId
699
                    );
700
                    foreach ($rows as $record) {
701
                        if (isset($record['folder_id']) && in_array($record['folder_id'], $listAllowedFolders) === false) {
702
                            array_push($listAllowedFolders, $record['folder_id']);
703
                        }
704
                        // Check if this group is allowed to modify any pw in allowed folders
705
                        if ($tmp['allow_pw_change'] == 1 && in_array($record['folder_id'], $listFoldersEditableByRole) === false) {
706
                            array_push($listFoldersEditableByRole, $record['folder_id']);
707
                        }
708
                    }
709
                    // Check for the users roles if some specific rights exist on items
710
                    $rows = DB::query(
711
                        "SELECT i.id_tree, r.item_id
712
                        FROM ".prefix_table("items")." as i
713
                        INNER JOIN ".prefix_table("restriction_to_roles")." as r ON (r.item_id=i.id)
714
                        WHERE r.role_id=%i
715
                        ORDER BY i.id_tree ASC",
716
                        $roleId
717
                    );
718
                    $inc = 0;
719
                    foreach ($rows as $record) {
720
                        if (isset($record['id_tree'])) {
721
                            $listFoldersLimited[$record['id_tree']][$inc] = $record['item_id'];
722
                            $inc++;
723
                        }
724
                    }
725
                }
726
            }
727
        }
728
        
729
        // Clean arrays
730
        $listAllowedFolders = array_unique($listAllowedFolders);
731
        $groupesVisiblesUser = explode(';', trimElement($groupesVisiblesUser, ";"));
732
        
733
        // Does this user is allowed to see other items
734
        $inc = 0;
735
        $rows = DB::query(
736
            "SELECT id, id_tree FROM ".prefix_table("items")."
737
            WHERE restricted_to LIKE %ss AND inactif=%s",
738
            $_SESSION['user_id'].';',
739
            '0'
740
        );
741
        foreach ($rows as $record) {
742
            // Exclude restriction on item if folder is fully accessible
743
            if (in_array($record['id_tree'], $listAllowedFolders) === false) {
744
                $listRestrictedFoldersForItems[$record['id_tree']][$inc] = $record['id'];
745
                $inc++;
746
            }
747
        }
748
        
749
        // => Build final lists
750
        // Add user allowed folders
751
        $allowedFoldersTmp = array_unique(
752
            array_merge($listAllowedFolders, $groupesVisiblesUser)
753
        );
754
        // Exclude from allowed folders all the specific user forbidden folders
755
        $allowedFolders = array();
756
        foreach ($allowedFoldersTmp as $ident) {
757
            if (!in_array($ident, $groupesInterditsUser) && !empty($ident)) {
758
                array_push($allowedFolders, $ident);
759
            }
760
        }
761
762
        // Clean array
763
        $listAllowedFolders = array_filter(array_unique($allowedFolders));
764
765
        // Exclude all PF
766
        $_SESSION['forbiden_pfs'] = array();
767
768
        $where = new WhereClause('and');
769
        $where->add('personal_folder=%i', 1);
770
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
771
            && isset($_SESSION['personal_folder']) === true && $_SESSION['personal_folder'] === '1'
772
        ) {
773
            $where->add('title=%s', $_SESSION['user_id']);
774
            $where->negateLast();
775
        }
776
777
        $persoFlds = DB::query(
778
            "SELECT id
779
            FROM ".prefix_table("nested_tree")."
780
            WHERE %l",
781
            $where
782
        );
783
        foreach ($persoFlds as $persoFldId) {
784
            array_push($_SESSION['forbiden_pfs'], $persoFldId['id']);
785
        }
786
        // Get IDs of personal folders
787
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1'
788
            && isset($_SESSION['personal_folder']) === true &&  $_SESSION['personal_folder'] === '1'
789
        ) {
790
            $persoFld = DB::queryfirstrow(
791
                "SELECT id
792
                FROM ".prefix_table("nested_tree")."
793
                WHERE title = %s AND personal_folder = %i",
794
                $_SESSION['user_id'],
795
                1
796
            );
797
            if (empty($persoFld['id']) === false) {
798
                if (in_array($persoFld['id'], $listAllowedFolders) === false) {
799
                    array_push($_SESSION['personal_folders'], $persoFld['id']);
800
                    array_push($listAllowedFolders, $persoFld['id']);
801
                    array_push($_SESSION['personal_visible_groups'], $persoFld['id']);
802
                    // get all descendants
803
                    $ids = $tree->getChildren($persoFld['id']);
804
                    foreach ($ids as $ident) {
805
                        array_push($listAllowedFolders, $ident->id);
806
                        array_push($_SESSION['personal_visible_groups'], $ident->id);
807
                        array_push($_SESSION['personal_folders'], $ident->id);
808
                    }
809
                }
810
            }
811
            // get list of readonly folders when pf is disabled.
812
            $_SESSION['personal_folders'] = array_unique($_SESSION['personal_folders']);
813
            // rule - if one folder is set as W or N in one of the Role, then User has access as W
814
            foreach ($listAllowedFolders as $folderId) {
815
                if (in_array($folderId, array_unique(array_merge($listReadOnlyFolders, $_SESSION['personal_folders']))) === false) {
816
                    DB::query(
817
                        "SELECT *
818
                        FROM ".prefix_table("roles_values")."
819
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
820
                        $folderId,
821
                        $fonctionsAssociees,
822
                        array("W", "ND", "NE", "NDNE")
823
                    );
824
                    if (DB::count() === 0 && in_array($folderId, $groupesVisiblesUser) === false) {
825
                        array_push($listReadOnlyFolders, $folderId);
826
                    }
827
                }
828
            }
829
        } else {
830
            // get list of readonly folders when pf is disabled.
831
            // rule - if one folder is set as W in one of the Role, then User has access as W
832
            foreach ($listAllowedFolders as $folderId) {
833
                if (in_array($folderId, $listReadOnlyFolders) === false) {
834
                    DB::query(
835
                        "SELECT *
836
                        FROM ".prefix_table("roles_values")."
837
                        WHERE folder_id = %i AND role_id IN %li AND type IN %ls",
838
                        $folderId,
839
                        $fonctionsAssociees,
840
                        array("W", "ND", "NE", "NDNE")
841
                    );
842
                    if (DB::count() == 0 && !in_array($folderId, $groupesVisiblesUser)) {
843
                        array_push($listReadOnlyFolders, $folderId);
844
                    }
845
                }
846
            }
847
        }
848
849
        // check if change proposals on User's items
850
        if (isset($SETTINGS['enable_suggestion']) === true && $SETTINGS['enable_suggestion'] === '1') {
851
            DB::query(
852
                "SELECT *
853
                FROM ".prefix_table("items_change")." AS c
854
                LEFT JOIN ".prefix_table("log_items")." AS i ON (c.item_id = i.id_item)
855
                WHERE i.action = %s AND i.id_user = %i",
856
                "at_creation",
857
                $_SESSION['user_id']
858
            );
859
            $_SESSION['nb_item_change_proposals'] = DB::count();
860
        } else {
861
            $_SESSION['nb_item_change_proposals'] = 0;
862
        }            
863
864
        $_SESSION['all_non_personal_folders'] = $listAllowedFolders;
865
        $_SESSION['groupes_visibles'] = $listAllowedFolders;
866
        $_SESSION['groupes_visibles_list'] = implode(',', $listAllowedFolders);
867
        $_SESSION['personal_visible_groups_list'] = implode(',', $_SESSION['personal_visible_groups']);
868
        $_SESSION['read_only_folders'] = $listReadOnlyFolders;
869
        $_SESSION['no_access_folders'] = $groupesInterdits;
870
871
        $_SESSION['list_folders_limited'] = $listFoldersLimited;
872
        $_SESSION['list_folders_editable_by_role'] = $listFoldersEditableByRole;
873
        $_SESSION['list_restricted_folders_for_items'] = $listRestrictedFoldersForItems;
874
        // Folders and Roles numbers
875
        DB::queryfirstrow("SELECT id FROM ".prefix_table("nested_tree")."");
876
        $_SESSION['nb_folders'] = DB::count();
877
        DB::queryfirstrow("SELECT id FROM ".prefix_table("roles_title"));
878
        $_SESSION['nb_roles'] = DB::count();
879
    }
880
881
    // update user's timestamp
882
    DB::update(
883
        prefix_table('users'),
884
        array(
885
            'timestamp' => time()
886
        ),
887
        "id=%i",
888
        $_SESSION['user_id']
889
    );
890
}
891
892
/**
893
 * updateCacheTable()
894
 *
895
 * Update the CACHE table
896
 * @param string $action
897
 */
898
function updateCacheTable($action, $ident = "")
899
{
900
    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...
901
    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...
902
903
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
904
905
    //Connect to DB
906
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
907
    $pass = defuse_return_decrypted($pass);
908
    DB::$host = $server;
909
    DB::$user = $user;
910
    DB::$password = $pass;
911
    DB::$dbName = $database;
912
    DB::$port = $port;
913
    DB::$encoding = $encoding;
914
    DB::$error_handler = true;
915
    $link = mysqli_connect($server, $user, $pass, $database, $port);
916
    $link->set_charset($encoding);
917
918
    //Load Tree
919
    $tree = new SplClassLoader('Tree\NestedTree', '../includes/libraries');
920
    $tree->register();
921
    $tree = new Tree\NestedTree\NestedTree(prefix_table("nested_tree"), 'id', 'parent_id', 'title');
922
923
    // Rebuild full cache table
924
    if ($action === "reload") {
925
        // truncate table
926
        DB::query("TRUNCATE TABLE ".prefix_table("cache"));
927
928
        // reload date
929
        $rows = DB::query(
930
            "SELECT *
931
            FROM ".prefix_table('items')." as i
932
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
933
            AND l.action = %s
934
            AND i.inactif = %i",
935
            'at_creation',
936
            0
937
        );
938
        foreach ($rows as $record) {
939
            if (empty($record['id_tree']) === false) {
940
                // Get all TAGS
941
                $tags = "";
942
                $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $record['id']);
943
                foreach ($itemTags as $itemTag) {
944
                    if (!empty($itemTag['tag'])) {
945
                        $tags .= $itemTag['tag']." ";
946
                    }
947
                }
948
                // Get renewal period
949
                $resNT = DB::queryfirstrow("SELECT renewal_period FROM ".prefix_table('nested_tree')." WHERE id=%i", $record['id_tree']);
950
951
                // form id_tree to full foldername
952
                $folder = "";
953
                $arbo = $tree->getPath($record['id_tree'], true);
954
                foreach ($arbo as $elem) {
955
                    if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
956
                        $elem->title = $_SESSION['login'];
957
                    }
958
                    if (empty($folder)) {
959
                        $folder = stripslashes($elem->title);
960
                    } else {
961
                        $folder .= " » ".stripslashes($elem->title);
962
                    }
963
                }
964
                // store data
965
                DB::insert(
966
                    prefix_table('cache'),
967
                    array(
968
                        'id' => $record['id'],
969
                        'label' => $record['label'],
970
                        'description' => isset($record['description']) ? $record['description'] : "",
971
                        'url' => (isset($record['url']) && !empty($record['url'])) ? $record['url'] : "0",
972
                        'tags' => $tags,
973
                        'id_tree' => $record['id_tree'],
974
                        'perso' => $record['perso'],
975
                        'restricted_to' => (isset($record['restricted_to']) && !empty($record['restricted_to'])) ? $record['restricted_to'] : "0",
976
                        'login' => isset($record['login']) ? $record['login'] : "",
977
                        'folder' => $folder,
978
                        'author' => $record['id_user'],
979
                        'renewal_period' => isset($resNT['renewal_period']) ? $resNT['renewal_period'] : "0",
980
                        'timestamp' => $record['date']
981
                        )
982
                );
983
            }
984
        }
985
        // UPDATE an item
986
    } elseif ($action === "update_value") {
987
        // get new value from db
988
        $data = DB::queryfirstrow(
989
            "SELECT label, description, id_tree, perso, restricted_to, login, url
990
            FROM ".prefix_table('items')."
991
            WHERE id=%i",
992
            $ident
993
        );
994
        // Get all TAGS
995
        $tags = "";
996
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id=%i", $ident);
997
        foreach ($itemTags as $itemTag) {
998
            if (!empty($itemTag['tag'])) {
999
                $tags .= $itemTag['tag']." ";
1000
            }
1001
        }
1002
        // form id_tree to full foldername
1003
        $folder = "";
1004
        $arbo = $tree->getPath($data['id_tree'], true);
1005
        foreach ($arbo as $elem) {
1006
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1007
                $elem->title = $_SESSION['login'];
1008
            }
1009
            if (empty($folder)) {
1010
                $folder = stripslashes($elem->title);
1011
            } else {
1012
                $folder .= " » ".stripslashes($elem->title);
1013
            }
1014
        }
1015
        // finaly update
1016
        DB::update(
1017
            prefix_table('cache'),
1018
            array(
1019
                'label' => $data['label'],
1020
                'description' => $data['description'],
1021
                'tags' => $tags,
1022
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1023
                'id_tree' => $data['id_tree'],
1024
                'perso' => $data['perso'],
1025
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1026
                'login' => isset($data['login']) ? $data['login'] : "",
1027
                'folder' => $folder,
1028
                'author' => $_SESSION['user_id'],
1029
                ),
1030
            "id = %i",
1031
            $ident
1032
        );
1033
        // ADD an item
1034
    } elseif ($action === "add_value") {
1035
        // get new value from db
1036
        $data = DB::queryFirstRow(
1037
            "SELECT i.label, i.description, i.id_tree as id_tree, i.perso, i.restricted_to, i.id, i.login, i.url, l.date
1038
            FROM ".prefix_table('items')." as i
1039
            INNER JOIN ".prefix_table('log_items')." as l ON (l.id_item = i.id)
1040
            WHERE i.id = %i
1041
            AND l.action = %s",
1042
            $ident,
1043
            'at_creation'
1044
        );
1045
        // Get all TAGS
1046
        $tags = "";
1047
        $itemTags = DB::query("SELECT tag FROM ".prefix_table('tags')." WHERE item_id = %i", $ident);
1048
        foreach ($itemTags as $itemTag) {
1049
            if (!empty($itemTag['tag'])) {
1050
                $tags .= $itemTag['tag']." ";
1051
            }
1052
        }
1053
        // form id_tree to full foldername
1054
        $folder = "";
1055
        $arbo = $tree->getPath($data['id_tree'], true);
1056
        foreach ($arbo as $elem) {
1057
            if ($elem->title == $_SESSION['user_id'] && $elem->nlevel == 1) {
1058
                $elem->title = $_SESSION['login'];
1059
            }
1060
            if (empty($folder)) {
1061
                $folder = stripslashes($elem->title);
1062
            } else {
1063
                $folder .= " » ".stripslashes($elem->title);
1064
            }
1065
        }
1066
        // finaly update
1067
        DB::insert(
1068
            prefix_table('cache'),
1069
            array(
1070
                'id' => $data['id'],
1071
                'label' => $data['label'],
1072
                'description' => $data['description'],
1073
                'tags' => (isset($tags) && !empty($tags)) ? $tags : "None",
1074
                'url' => (isset($data['url']) && !empty($data['url'])) ? $data['url'] : "0",
1075
                'id_tree' => $data['id_tree'],
1076
                'perso' => (isset($data['perso']) && !empty($data['perso']) && $data['perso'] !== "None") ? $data['perso'] : "0",
1077
                'restricted_to' => (isset($data['restricted_to']) && !empty($data['restricted_to'])) ? $data['restricted_to'] : "0",
1078
                'login' => isset($data['login']) ? $data['login'] : "",
1079
                'folder' => $folder,
1080
                'author' => $_SESSION['user_id'],
1081
                'timestamp' => $data['date']
1082
            )
1083
        );
1084
1085
        // DELETE an item
1086
    } elseif ($action === "delete_value") {
1087
        DB::delete(prefix_table('cache'), "id = %i", $ident);
1088
    }
1089
}
1090
1091
/*
1092
*
1093
*/
1094
function getStatisticsData()
1095
{
1096
    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...
1097
1098
    DB::query(
1099
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1100
        0
1101
    );
1102
    $counter_folders = DB::count();
1103
1104
    DB::query(
1105
        "SELECT id FROM ".prefix_table("nested_tree")." WHERE personal_folder = %i",
1106
        1
1107
    );
1108
    $counter_folders_perso = DB::count();
1109
1110
    DB::query(
1111
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1112
        0
1113
    );
1114
    $counter_items = DB::count();
1115
1116
    DB::query(
1117
        "SELECT id FROM ".prefix_table("items")." WHERE perso = %i",
1118
        1
1119
    );
1120
    $counter_items_perso = DB::count();
1121
1122
    DB::query(
1123
        "SELECT id FROM ".prefix_table("users").""
1124
    );
1125
    $counter_users = DB::count();
1126
1127
    DB::query(
1128
        "SELECT id FROM ".prefix_table("users")." WHERE admin = %i",
1129
        1
1130
    );
1131
    $admins = DB::count();
1132
1133
    DB::query(
1134
        "SELECT id FROM ".prefix_table("users")." WHERE gestionnaire = %i",
1135
        1
1136
    );
1137
    $managers = DB::count();
1138
1139
    DB::query(
1140
        "SELECT id FROM ".prefix_table("users")." WHERE read_only = %i",
1141
        1
1142
    );
1143
    $readOnly = DB::count();
1144
1145
    // list the languages
1146
    $usedLang = [];
1147
    $tp_languages = DB::query(
1148
        "SELECT name FROM ".prefix_table("languages")
1149
    );
1150
    foreach ($tp_languages as $tp_language) {
1151
        DB::query(
1152
            "SELECT * FROM ".prefix_table("users")." WHERE user_language = %s",
1153
            $tp_language['name']
1154
        );
1155
        $usedLang[$tp_language['name']] = round((DB::count() * 100 / $counter_users), 0);
1156
    }
1157
1158
    // get list of ips
1159
    $usedIp = [];
1160
    $tp_ips = DB::query(
1161
        "SELECT user_ip FROM ".prefix_table("users")
1162
    );
1163
    foreach ($tp_ips as $ip) {
1164
        if (array_key_exists($ip['user_ip'], $usedIp)) {
1165
            $usedIp[$ip['user_ip']] = $usedIp[$ip['user_ip']] + 1;
1166
        } elseif (!empty($ip['user_ip']) && $ip['user_ip'] !== "none") {
1167
            $usedIp[$ip['user_ip']] = 1;
1168
        }
1169
    }
1170
1171
    return array(
1172
        "error" => "",
1173
        "stat_phpversion" => phpversion(),
1174
        "stat_folders" => $counter_folders,
1175
        "stat_folders_shared" => intval($counter_folders) - intval($counter_folders_perso),
1176
        "stat_items" => $counter_items,
1177
        "stat_items_shared" => intval($counter_items) - intval($counter_items_perso),
1178
        "stat_users" => $counter_users,
1179
        "stat_admins" => $admins,
1180
        "stat_managers" => $managers,
1181
        "stat_ro" => $readOnly,
1182
        "stat_kb" => $SETTINGS['enable_kb'],
1183
        "stat_pf" => $SETTINGS['enable_pf_feature'],
1184
        "stat_fav" => $SETTINGS['enable_favourites'],
1185
        "stat_teampassversion" => $SETTINGS['cpassman_version'],
1186
        "stat_ldap" => $SETTINGS['ldap_mode'],
1187
        "stat_agses" => $SETTINGS['agses_authentication_enabled'],
1188
        "stat_duo" => $SETTINGS['duo'],
1189
        "stat_suggestion" => $SETTINGS['enable_suggestion'],
1190
        "stat_api" => $SETTINGS['api'],
1191
        "stat_customfields" => $SETTINGS['item_extra_fields'],
1192
        "stat_syslog" => $SETTINGS['syslog_enable'],
1193
        "stat_2fa" => $SETTINGS['google_authentication'],
1194
        "stat_stricthttps" => $SETTINGS['enable_sts'],
1195
        "stat_mysqlversion" => DB::serverVersion(),
1196
        "stat_languages" => $usedLang,
1197
        "stat_country" => $usedIp
1198
    );
1199
}
1200
1201
/**
1202
 * Permits to send an email
1203
 *
1204
 * @param  string $subject     email subject
1205
 * @param  string $textMail    email message
1206
 * @param  string $email       email
1207
 * @param  array  $LANG        Language
1208
 * @param  array  $SETTINGS    settings
1209
 * @param  string $textMailAlt email message alt
1210
 * @return  string  some json info
1211
 */
1212
function sendEmail(
1213
    $subject,
1214
    $textMail,
1215
    $email,
1216
    $LANG,
1217
    $SETTINGS,
1218
    $textMailAlt = ""
1219
) {
1220
    // CAse where email not defined
1221
    if ($email === "none") {
1222
        return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1223
    }
1224
1225
    // Load settings
1226
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
1227
1228
    // Load superglobal
1229
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
1230
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
1231
1232
    // Get user language
1233
    $session_user_language = $superGlobal->get("user_language", "SESSION");
1234
    $user_language = isset($session_user_language) ? $session_user_language : "english";
1235
    require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$user_language.'.php';
1236
1237
    // Load library
1238
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1239
1240
    // load PHPMailer
1241
    $mail = new SplClassLoader('Email\PHPMailer', '../includes/libraries');
1242
    $mail->register();
1243
    $mail = new Email\PHPMailer\PHPMailer(true);
1244
    try {
1245
        // send to user
1246
        $mail->setLanguage("en", $SETTINGS['cpassman_dir']."/includes/libraries/Email/PHPMailer/language/");
1247
        $mail->SMTPDebug = 0; //value 1 can be used to debug - 4 for debuging connections
1248
        $mail->Port = $SETTINGS['email_port']; //COULD BE USED
1249
        $mail->CharSet = "utf-8";
1250
        if ($SETTINGS['email_security'] === "tls" || $SETTINGS['email_security'] === "ssl") {
1251
            $mail->SMTPSecure = $SETTINGS['email_security'];
1252
            $SMTPAutoTLS = true;
1253
        } else {
1254
            $SMTPAutoTLS = false;
1255
            $mail->SMTPSecure = "";
1256
        }
1257
        $mail->SMTPAutoTLS = $SMTPAutoTLS;
1258
        $mail->isSmtp(); // send via SMTP
1259
        $mail->Host = $SETTINGS['email_smtp_server']; // SMTP servers
1260
        $mail->SMTPAuth = $SETTINGS['email_smtp_auth'] == '1' ? true : false; // turn on SMTP authentication
1261
        $mail->Username = $SETTINGS['email_auth_username']; // SMTP username
1262
        $mail->Password = $SETTINGS['email_auth_pwd']; // SMTP password
1263
        $mail->From = $SETTINGS['email_from'];
1264
        $mail->FromName = $SETTINGS['email_from_name'];
1265
1266
        // Prepare for each person
1267
        $dests = explode(",", $email);
1268
        foreach ($dests as $dest) {
1269
            $mail->addAddress($dest);
1270
        }
1271
1272
        // Prepare HTML
1273
        $text_html = '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.=
1274
        w3.org/TR/html4/loose.dtd"><html>
1275
        <head><title>Email Template</title>
1276
        <style type="text/css">
1277
        body { background-color: #f0f0f0; padding: 10px 0; margin:0 0 10px =0; }
1278
        </style></head>
1279
        <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">
1280
        <table border="0" width="100%" height="100%" cellpadding="0" cellspacing="0" bgcolor="#f0f0f0" style="border-spacing: 0;">
1281
        <tr><td style="border-collapse: collapse;"><br>
1282
            <table border="0" width="100%" cellpadding="0" cellspacing="0" bgcolor="#17357c" style="border-spacing: 0; margin-bottom: 25px;">
1283
            <tr><td style="border-collapse: collapse; padding: 11px 20px;">
1284
                <div style="max-width:150px; max-height:34px; color:#f0f0f0; font-weight:bold;">Teampass</div>
1285
            </td></tr></table></td>
1286
        </tr>
1287
        <tr><td align="center" valign="top" bgcolor="#f0f0f0" style="border-collapse: collapse; background-color: #f0f0f0;">
1288
            <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;">
1289
            <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;">
1290
            <br><div style="float:right;">'.
1291
        $textMail.
1292
        '<br><br></td></tr></table>
1293
        </td></tr></table>
1294
        <br></body></html>';
1295
1296
        $mail->WordWrap = 80; // set word wrap
1297
        $mail->isHtml(true); // send as HTML
1298
        $mail->Subject = $subject;
1299
        $mail->Body = $text_html;
1300
        $mail->AltBody = $textMailAlt;
1301
        // send email
1302
        if (!$mail->send()) {
1303
            return '"error":"error_mail_not_send" , "message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1304
        } else {
1305
            return '"error":"" , "message":"'.$LANG['forgot_my_pw_email_sent'].'"';
1306
        }
1307
    } catch (Exception $e) {
1308
        return '"error":"error_mail_not_send" , '.
1309
        '"message":"'.str_replace(array("\n", "\t", "\r"), '', $mail->ErrorInfo).'"';
1310
    }
1311
}
1312
1313
/**
1314
 * generateKey()
1315
 *
1316
 * @return
1317
 */
1318
function generateKey()
1319
{
1320
    return substr(md5(rand().rand()), 0, 15);
1321
}
1322
1323
/**
1324
 * dateToStamp()
1325
 *
1326
 * @return
1327
 */
1328
function dateToStamp($date)
1329
{
1330
    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...
1331
1332
    $date = date_parse_from_format($SETTINGS['date_format'], $date);
1333
    if ($date['warning_count'] == 0 && $date['error_count'] == 0) {
1334
        return mktime(23, 59, 59, $date['month'], $date['day'], $date['year']);
1335
    } else {
1336
        return false;
1337
    }
1338
}
1339
1340
function isDate($date)
1341
{
1342
    return (strtotime($date) !== false);
1343
}
1344
1345
/**
1346
 * isUTF8()
1347
 *
1348
 * @return integer is the string in UTF8 format.
1349
 */
1350
1351
function isUTF8($string)
1352
{
1353
    if (is_array($string) === true) {
1354
        $string = $string['string'];
1355
    }
1356
    return preg_match(
1357
        '%^(?:
1358
        [\x09\x0A\x0D\x20-\x7E] # ASCII
1359
        | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
1360
        | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
1361
        | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
1362
        | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
1363
        | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
1364
        | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
1365
        | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
1366
        )*$%xs',
1367
        $string
1368
    );
1369
}
1370
1371
/*
1372
* FUNCTION
1373
* permits to prepare data to be exchanged
1374
*/
1375
/**
1376
 * @param string $type
1377
 */
1378
function prepareExchangedData($data, $type)
1379
{
1380
    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...
1381
1382
    //load ClassLoader
1383
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1384
    //Load AES
1385
    $aes = new SplClassLoader('Encryption\Crypt', $SETTINGS['cpassman_dir'].'/includes/libraries');
1386
    $aes->register();
1387
1388
    if ($type == "encode") {
1389
        if (isset($SETTINGS['encryptClientServer'])
1390
            && $SETTINGS['encryptClientServer'] === "0"
1391
        ) {
1392
            return json_encode(
1393
                $data,
1394
                JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1395
            );
1396
        } else {
1397
            return Encryption\Crypt\aesctr::encrypt(
1398
                json_encode(
1399
                    $data,
1400
                    JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP
1401
                ),
1402
                $_SESSION['key'],
1403
                256
1404
            );
1405
        }
1406
    } elseif ($type == "decode") {
1407
        if (isset($SETTINGS['encryptClientServer'])
1408
            && $SETTINGS['encryptClientServer'] === "0"
1409
        ) {
1410
            return json_decode(
1411
                $data,
1412
                true
1413
            );
1414
        } else {
1415
            return json_decode(
1416
                Encryption\Crypt\aesctr::decrypt(
1417
                    $data,
1418
                    $_SESSION['key'],
1419
                    256
1420
                ),
1421
                true
1422
            );
1423
        }
1424
    }
1425
}
1426
1427
function make_thumb($src, $dest, $desired_width)
1428
{
1429
    /* read the source image */
1430
    $source_image = imagecreatefrompng($src);
1431
    $width = imagesx($source_image);
1432
    $height = imagesy($source_image);
1433
1434
    /* find the "desired height" of this thumbnail, relative to the desired width  */
1435
    $desired_height = floor($height * ($desired_width / $width));
1436
1437
    /* create a new, "virtual" image */
1438
    $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

1438
    $virtual_image = imagecreatetruecolor($desired_width, /** @scrutinizer ignore-type */ $desired_height);
Loading history...
1439
1440
    /* copy source image at a resized size */
1441
    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

1441
    imagecopyresampled($virtual_image, $source_image, 0, 0, 0, 0, $desired_width, /** @scrutinizer ignore-type */ $desired_height, $width, $height);
Loading history...
1442
1443
    /* create the physical thumbnail image to its destination */
1444
    imagejpeg($virtual_image, $dest);
1445
}
1446
1447
/*
1448
** check table prefix in SQL query
1449
*/
1450
/**
1451
 * @param string $table
1452
 */
1453
function prefix_table($table)
1454
{
1455
    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...
1456
    $safeTable = htmlspecialchars($pre.$table);
1457
    if (!empty($safeTable)) {
1458
        // sanitize string
1459
        return $safeTable;
1460
    } else {
1461
        // stop error no table
1462
        return "table_not_exists";
1463
    }
1464
}
1465
1466
/*
1467
 * Creates a KEY using PasswordLib
1468
 */
1469
function GenerateCryptKey($size = "", $secure = false, $numerals = false, $capitalize = false, $symbols = false)
1470
{
1471
    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...
1472
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
1473
1474
    if ($secure === true) {
1475
        $numerals = true;
1476
        $capitalize = true;
1477
        $symbols = true;
1478
    }
1479
1480
    // Load libraries
1481
    $generator = new SplClassLoader('PasswordGenerator\Generator', '../includes/libraries');
1482
    $generator->register();
1483
    $generator = new PasswordGenerator\Generator\ComputerPasswordGenerator();
1484
1485
    // Can we use PHP7 random_int function?
1486
    if (version_compare(phpversion(), '7.0', '>=')) {
1487
        require_once $SETTINGS['cpassman_dir'].'/includes/libraries/PasswordGenerator/RandomGenerator/Php7RandomGenerator.php';
1488
         $generator->setRandomGenerator(new PasswordGenerator\RandomGenerator\Php7RandomGenerator());
1489
    }
1490
1491
    // init
1492
    if (empty($size) === false) {
1493
        $generator->setLength(intval($size));
1494
    }
1495
    if (empty($numerals) === false) {
1496
        $generator->setNumbers($numerals);
1497
    }
1498
    if (empty($capitalize) === false) {
1499
        $generator->setUppercase($capitalize);
1500
    }
1501
    if (empty($symbols) === false) {
1502
        $generator->setSymbols($symbols);
1503
    }
1504
1505
    // generate and send back
1506
    return $generator->generatePassword();
1507
}
1508
1509
/*
1510
* Send sysLOG message
1511
* @param string $message
1512
* @param string $host
1513
*/
1514
function send_syslog($message, $host, $port, $component = "teampass")
1515
{
1516
    $sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
1517
    $syslog_message = "<123>".date('M d H:i:s ').$component.": ".$message;
1518
    socket_sendto($sock, $syslog_message, strlen($syslog_message), 0, $host, $port);
1519
    socket_close($sock);
1520
}
1521
1522
1523
1524
/**
1525
 * logEvents()
1526
 *
1527
 * permits to log events into DB
1528
 * @param string $type
1529
 * @param string $label
1530
 * @param string $field_1
1531
 */
1532
function logEvents($type, $label, $who, $login = "", $field_1 = null)
1533
{
1534
    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...
1535
    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...
1536
1537
    if (empty($who)) {
1538
        $who = get_client_ip_server();
1539
    }
1540
1541
    // include librairies & connect to DB
1542
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1543
    $pass = defuse_return_decrypted($pass);
1544
    DB::$host = $server;
1545
    DB::$user = $user;
1546
    DB::$password = $pass;
1547
    DB::$dbName = $database;
1548
    DB::$port = $port;
1549
    DB::$encoding = $encoding;
1550
    DB::$error_handler = true;
1551
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1552
    $link->set_charset($encoding);
1553
1554
    DB::insert(
1555
        prefix_table("log_system"),
1556
        array(
1557
            'type' => $type,
1558
            'date' => time(),
1559
            'label' => $label,
1560
            'qui' => $who,
1561
            'field_1' => $field_1 === null ? "" : $field_1
1562
        )
1563
    );
1564
    if (isset($SETTINGS['syslog_enable']) && $SETTINGS['syslog_enable'] == 1) {
1565
        if ($type == "user_mngt") {
1566
            send_syslog(
1567
                'action='.str_replace('at_', '', $label).' attribute=user user='.$who.' userid="'.$login.'" change="'.$field_1.'" ',
1568
                $SETTINGS['syslog_host'],
1569
                $SETTINGS['syslog_port'],
1570
                "teampass"
1571
            );
1572
        } else {
1573
            send_syslog(
1574
                'action='.$type.' attribute='.$label.' user='.$who.' userid="'.$login.'" ',
1575
                $SETTINGS['syslog_host'],
1576
                $SETTINGS['syslog_port'],
1577
                "teampass"
1578
            );
1579
        }
1580
    }
1581
}
1582
1583
/**
1584
 * Logs sent events
1585
 *
1586
 * @param string $ident
1587
 * @param string $item
1588
 * @param string $id_user
1589
 * @param string $action
1590
 * @param string $login
1591
 * @param string $raison
1592
 * @param string $raison_iv
1593
 * @param string $encryption_type
1594
 * @return void
1595
 */
1596
function logItems(
1597
    $item_id,
1598
    $item_label,
1599
    $id_user,
1600
    $action,
1601
    $login = "",
1602
    $raison = null,
1603
    $raison_iv = null,
1604
    $encryption_type = ""
1605
)
1606
{
1607
    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...
1608
    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...
1609
    $dataItem = '';
1610
1611
    // include librairies & connect to DB
1612
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1613
    $pass = defuse_return_decrypted($pass);
1614
    DB::$host = $server;
1615
    DB::$user = $user;
1616
    DB::$password = $pass;
1617
    DB::$dbName = $database;
1618
    DB::$port = $port;
1619
    DB::$encoding = $encoding;
1620
    DB::$error_handler = true;
1621
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1622
    $link->set_charset($encoding);
1623
1624
    // Insert log in DB
1625
    DB::insert(
1626
        prefix_table("log_items"),
1627
        array(
1628
            'id_item' => $item_id,
1629
            'date' => time(),
1630
            'id_user' => $id_user,
1631
            'action' => $action,
1632
            'raison' => $raison,
1633
            'raison_iv' => $raison_iv,
1634
            'encryption_type' => $encryption_type
1635
        )
1636
    );
1637
1638
    // SYSLOG
1639
    if (isset($SETTINGS['syslog_enable']) === true && $SETTINGS['syslog_enable'] === '1') {
1640
        // Extract reason
1641
        $attribute = explode(' : ', $raison);
1642
1643
        // Get item info if not known
1644
        if (empty($item_label) === true) {
1645
            $dataItem = DB::queryfirstrow(
1646
                "SELECT id, id_tree, label
1647
                FROM ".prefix_table("items")."
1648
                WHERE id = %i",
1649
                $item_id
1650
            );
1651
1652
            $item_label = $dataItem['label'];
1653
        }
1654
1655
        send_syslog(
1656
            'action='.str_replace('at_', '', $action).' attribute='.str_replace('at_', '', $attribute[0]).' itemno='.$item_id.' user='.addslashes($login).' itemname="'.addslashes($item_label).'"',
1657
            $SETTINGS['syslog_host'],
1658
            $SETTINGS['syslog_port'],
1659
            "teampass"
1660
        );
1661
    }
1662
1663
    // send notification if enabled
1664
    if (isset($SETTINGS['enable_email_notification_on_item_shown']) === true
1665
        && $SETTINGS['enable_email_notification_on_item_shown'] === '1'
1666
        && $action === 'at_shown'
1667
    ) {
1668
        // Get info about item
1669
        if (empty($dataItem) === true && empty($item_label) === true) {
1670
            $dataItem = DB::queryfirstrow(
1671
                "SELECT id, id_tree, label
1672
                FROM ".prefix_table("items")."
1673
                WHERE id = %i",
1674
                $item_id
1675
            );
1676
            $item_label = $dataItem['label'];
1677
        }
1678
1679
        // send back infos
1680
        DB::insert(
1681
            prefix_table('emails'),
1682
            array(
1683
                'timestamp' => time(),
1684
                '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...
1685
                'body' => str_replace(
1686
                    array('#tp_user#', '#tp_item#', '#tp_link#'),
1687
                    array(
1688
                        addslashes($_SESSION['login']),
1689
                        addslashes($item_label),
1690
                        $SETTINGS['cpassman_url']."/index.php?page=items&group=".$dataItem['id_tree']."&id=".$dataItem['id']
1691
                    ),
1692
                    $LANG['email_on_open_notification_mail']
1693
                ),
1694
                'receivers' => $_SESSION['listNotificationEmails'],
1695
                'status' => ''
1696
            )
1697
        );
1698
    }
1699
}
1700
1701
/*
1702
* Function to get the client ip address
1703
 */
1704
function get_client_ip_server()
1705
{
1706
    if (getenv('HTTP_CLIENT_IP')) {
1707
            $ipaddress = getenv('HTTP_CLIENT_IP');
1708
    } elseif (getenv('HTTP_X_FORWARDED_FOR')) {
1709
            $ipaddress = getenv('HTTP_X_FORWARDED_FOR');
1710
    } elseif (getenv('HTTP_X_FORWARDED')) {
1711
            $ipaddress = getenv('HTTP_X_FORWARDED');
1712
    } elseif (getenv('HTTP_FORWARDED_FOR')) {
1713
            $ipaddress = getenv('HTTP_FORWARDED_FOR');
1714
    } elseif (getenv('HTTP_FORWARDED')) {
1715
            $ipaddress = getenv('HTTP_FORWARDED');
1716
    } elseif (getenv('REMOTE_ADDR')) {
1717
            $ipaddress = getenv('REMOTE_ADDR');
1718
    } else {
1719
            $ipaddress = 'UNKNOWN';
1720
    }
1721
1722
    return $ipaddress;
1723
}
1724
1725
/**
1726
 * Escape all HTML, JavaScript, and CSS
1727
 *
1728
 * @param string $input The input string
1729
 * @param string $encoding Which character encoding are we using?
1730
 * @return string
1731
 */
1732
function noHTML($input, $encoding = 'UTF-8')
1733
{
1734
    return htmlspecialchars($input, ENT_QUOTES | ENT_XHTML, $encoding, false);
1735
}
1736
1737
/**
1738
 * handleConfigFile()
1739
 *
1740
 * permits to handle the Teampass config file
1741
 * $action accepts "rebuild" and "update"
1742
 */
1743
function handleConfigFile($action, $field = null, $value = null)
1744
{
1745
    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...
1746
    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...
1747
1748
    $tp_config_file = "../includes/config/tp.config.php";
1749
1750
    // include librairies & connect to DB
1751
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1752
    $pass = defuse_return_decrypted($pass);
1753
    DB::$host = $server;
1754
    DB::$user = $user;
1755
    DB::$password = $pass;
1756
    DB::$dbName = $database;
1757
    DB::$port = $port;
1758
    DB::$encoding = $encoding;
1759
    DB::$error_handler = true;
1760
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1761
    $link->set_charset($encoding);
1762
1763
    if (!file_exists($tp_config_file) || $action == "rebuild") {
1764
        // perform a copy
1765
        if (file_exists($tp_config_file)) {
1766
            if (!copy($tp_config_file, $tp_config_file.'.'.date("Y_m_d_His", time()))) {
1767
                return "ERROR: Could not copy file '".$tp_config_file."'";
1768
            }
1769
        }
1770
1771
        // regenerate
1772
        $data = array();
1773
        $data[0] = "<?php\n";
1774
        $data[1] = "global \$SETTINGS;\n";
1775
        $data[2] = "\$SETTINGS = array (\n";
1776
        $rows = DB::query(
1777
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s",
1778
            "admin"
1779
        );
1780
        foreach ($rows as $record) {
1781
            array_push($data, "    '".$record['intitule']."' => '".$record['valeur']."',\n");
1782
        }
1783
        array_push($data, ");\n");
1784
        $data = array_unique($data);
1785
    } elseif ($action == "update" && empty($field) === false) {
1786
        $data = file($tp_config_file);
1787
        $inc = 0;
1788
        $bFound = false;
1789
        foreach ($data as $line) {
1790
            if (stristr($line, ");")) {
1791
                break;
1792
            }
1793
1794
            //
1795
            if (stristr($line, "'".$field."' => '")) {
1796
                $data[$inc] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n";
1797
                $bFound = true;
1798
                break;
1799
            }
1800
            $inc++;
1801
        }
1802
        if ($bFound === false) {
1803
            $data[($inc)] = "    '".$field."' => '".filter_var($value, FILTER_SANITIZE_STRING)."',\n);\n";
1804
        }
1805
    }
1806
1807
    // update file
1808
    file_put_contents($tp_config_file, implode('', isset($data) ? $data : array()));
1809
1810
    return true;
1811
}
1812
1813
/*
1814
** Permits to replace &#92; to permit correct display
1815
*/
1816
/**
1817
 * @param string $input
1818
 */
1819
function handleBackslash($input)
1820
{
1821
    return str_replace("&amp;#92;", "&#92;", $input);
1822
}
1823
1824
/*
1825
** Permits to loas settings
1826
*/
1827
function loadSettings()
1828
{
1829
    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...
1830
1831
    /* LOAD CPASSMAN SETTINGS */
1832
    if (!isset($SETTINGS['loaded']) || $SETTINGS['loaded'] != 1) {
1833
        $SETTINGS['duplicate_folder'] = 0; //by default, this is set to 0;
1834
        $SETTINGS['duplicate_item'] = 0; //by default, this is set to 0;
1835
        $SETTINGS['number_of_used_pw'] = 5; //by default, this value is set to 5;
1836
        $settings = array();
1837
1838
        $rows = DB::query(
1839
            "SELECT * FROM ".prefix_table("misc")." WHERE type=%s_type OR type=%s_type2",
1840
            array(
1841
                'type' => "admin",
1842
                'type2' => "settings"
1843
            )
1844
        );
1845
        foreach ($rows as $record) {
1846
            if ($record['type'] == 'admin') {
1847
                $SETTINGS[$record['intitule']] = $record['valeur'];
1848
            } else {
1849
                $settings[$record['intitule']] = $record['valeur'];
1850
            }
1851
        }
1852
        $SETTINGS['loaded'] = 1;
1853
        $SETTINGS['default_session_expiration_time'] = 5;
1854
    }
1855
}
1856
1857
/*
1858
** check if folder has custom fields.
1859
** Ensure that target one also has same custom fields
1860
*/
1861
function checkCFconsistency($source_id, $target_id)
1862
{
1863
    $source_cf = array();
1864
    $rows = DB::QUERY(
1865
        "SELECT id_category
1866
        FROM ".prefix_table("categories_folders")."
1867
        WHERE id_folder = %i",
1868
        $source_id
1869
    );
1870
    foreach ($rows as $record) {
1871
        array_push($source_cf, $record['id_category']);
1872
    }
1873
1874
    $target_cf = array();
1875
    $rows = DB::QUERY(
1876
        "SELECT id_category
1877
        FROM ".prefix_table("categories_folders")."
1878
        WHERE id_folder = %i",
1879
        $target_id
1880
    );
1881
    foreach ($rows as $record) {
1882
        array_push($target_cf, $record['id_category']);
1883
    }
1884
1885
    $cf_diff = array_diff($source_cf, $target_cf);
1886
    if (count($cf_diff) > 0) {
1887
        return false;
1888
    }
1889
1890
    return true;
1891
}
1892
1893
/*
1894
*
1895
*/
1896
function encrypt_or_decrypt_file($filename_to_rework, $filename_status)
1897
{
1898
    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...
1899
    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...
1900
1901
    // Include librairies & connect to DB
1902
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
1903
    $pass = defuse_return_decrypted($pass);
1904
    DB::$host = $server;
1905
    DB::$user = $user;
1906
    DB::$password = $pass;
1907
    DB::$dbName = $database;
1908
    DB::$port = $port;
1909
    DB::$encoding = $encoding;
1910
    DB::$error_handler = true;
1911
    $link = mysqli_connect($server, $user, $pass, $database, $port);
1912
    $link->set_charset($encoding);
1913
1914
    // Get file info in DB
1915
    $fileInfo = DB::queryfirstrow(
1916
        "SELECT id FROM ".prefix_table("files")." WHERE file = %s",
1917
        filter_var($filename_to_rework, FILTER_SANITIZE_STRING)
1918
    );
1919
    if (empty($fileInfo['id']) === false) {
1920
        // Load PhpEncryption library
1921
        $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
1922
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
1923
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
1924
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
1925
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
1926
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
1927
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
1928
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
1929
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
1930
        require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
1931
1932
        // Get KEY
1933
        $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...
1934
1935
        if (isset($SETTINGS['enable_attachment_encryption'])
1936
            && $SETTINGS['enable_attachment_encryption'] === "1" &&
1937
            isset($filename_status)
1938
            && ($filename_status === "clear"
1939
                || $filename_status === "0")
1940
        ) {
1941
            // File needs to be encrypted
1942
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1943
                // Make a copy of file
1944
                if (!copy(
1945
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1946
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
1947
                )) {
1948
                    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...
1949
                } else {
1950
                    // Do a bck
1951
                    copy(
1952
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1953
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
1954
                    );
1955
                }
1956
1957
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
1958
1959
                // Now encrypt the file with saltkey
1960
                $err = '';
1961
                try {
1962
                    \Defuse\Crypto\File::encryptFile(
1963
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
1964
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
1965
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
1966
                    );
1967
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
1968
                    $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.";
1969
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
1970
                    $err = $ex;
1971
                } catch (Defuse\Crypto\Exception\IOException $ex) {
1972
                    $err = $ex;
1973
                }
1974
                if (empty($err) === false) {
1975
                    echo $err;
1976
                }
1977
1978
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
1979
1980
                // update table
1981
                DB::update(
1982
                    prefix_table('files'),
1983
                    array(
1984
                        'status' => 'encrypted'
1985
                        ),
1986
                    "id = %i",
1987
                    $fileInfo['id']
1988
                );
1989
            }
1990
        } elseif (isset($SETTINGS['enable_attachment_encryption'])
1991
            && $SETTINGS['enable_attachment_encryption'] === "0"
1992
            && isset($filename_status)
1993
            && $filename_status === "encrypted"
1994
        ) {
1995
            // file needs to be decrypted
1996
            if (file_exists($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework)) {
1997
                // make a copy of file
1998
                if (!copy(
1999
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2000
                    $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy"
2001
                )) {
2002
                    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...
2003
                } else {
2004
                    // do a bck
2005
                    copy(
2006
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2007
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".bck"
2008
                    );
2009
                }
2010
2011
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework);
2012
2013
                // Now encrypt the file with saltkey
2014
                $err = '';
2015
                try {
2016
                    \Defuse\Crypto\File::decryptFile(
2017
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy",
2018
                        $SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework,
2019
                        \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2020
                    );
2021
                } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2022
                    $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.";
2023
                } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2024
                    $err = $ex;
2025
                } catch (Defuse\Crypto\Exception\IOException $ex) {
2026
                    $err = $ex;
2027
                }
2028
                if (empty($err) === false) {
2029
                    echo $err;
2030
                }
2031
2032
                unlink($SETTINGS['path_to_upload_folder'].'/'.$filename_to_rework.".copy");
2033
2034
                // update table
2035
                DB::update(
2036
                    prefix_table('files'),
2037
                    array(
2038
                        'status' => 'clear'
2039
                        ),
2040
                    "id = %i",
2041
                    $fileInfo['id']
2042
                );
2043
            }
2044
        }
2045
    }
2046
2047
    // Exit
2048
    return false;
2049
}
2050
2051
/**
2052
 * Will encrypte/decrypt a fil eusing Defuse
2053
 * @param  string $type        can be either encrypt or decrypt
2054
 * @param  string $source_file path to source file
2055
 * @param  string $target_file path to target file
2056
 * @return string              'true' is success or error message
2057
 */
2058
function prepareFileWithDefuse($type, $source_file, $target_file, $password = '')
2059
{
2060
    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...
2061
2062
    // Load AntiXSS
2063
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2064
    $antiXss = new protect\AntiXSS\AntiXSS();
2065
2066
    // Protect against bad inputs
2067
    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...
2068
        return 'error_cannot_be_array';
2069
    }
2070
2071
    // Sanitize
2072
    $source_file = $antiXss->xss_clean($source_file);
2073
    $target_file = $antiXss->xss_clean($target_file);
2074
2075
    // load PhpEncryption library
2076
    $path_to_encryption = '/includes/libraries/Encryption/Encryption/';
2077
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Crypto.php';
2078
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Encoding.php';
2079
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'DerivedKeys.php';
2080
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Key.php';
2081
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyOrPassword.php';
2082
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'File.php';
2083
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'RuntimeTests.php';
2084
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'KeyProtectedByPassword.php';
2085
    require_once $SETTINGS['cpassman_dir'].$path_to_encryption.'Core.php';
2086
2087
    if (empty($password) === true) {
2088
    /*
2089
    File encryption/decryption is done with the SALTKEY
2090
     */
2091
2092
        // get KEY
2093
        $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...
2094
2095
        // Now perform action on the file
2096
        $err = '';
2097
        if ($type === 'decrypt') {
2098
            try {
2099
                \Defuse\Crypto\File::decryptFile(
2100
                    $source_file,
2101
                    $target_file,
2102
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2103
                );
2104
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2105
                $err = "decryption_not_possible";
2106
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2107
                $err = $ex;
2108
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2109
                $err = $ex;
2110
            }
2111
        } elseif ($type === 'encrypt') {
2112
            try {
2113
                \Defuse\Crypto\File::encryptFile(
2114
                    $source_file,
2115
                    $target_file,
2116
                    \Defuse\Crypto\Key::loadFromAsciiSafeString($ascii_key)
2117
                );
2118
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2119
                $err = "encryption_not_possible";
2120
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2121
                $err = $ex;
2122
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2123
                $err = $ex;
2124
            }
2125
        }
2126
    } else {
2127
    /*
2128
    File encryption/decryption is done with special password and not the SALTKEY
2129
     */
2130
2131
        $err = '';
2132
        if ($type === 'decrypt') {
2133
            try {
2134
                \Defuse\Crypto\File::decryptFileWithPassword(
2135
                    $source_file,
2136
                    $target_file,
2137
                    $password
2138
                );
2139
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2140
                $err = "wrong_key";
2141
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2142
                $err = $ex;
2143
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2144
                $err = $ex;
2145
            }
2146
        } elseif ($type === 'encrypt') {
2147
            try {
2148
                \Defuse\Crypto\File::encryptFileWithPassword(
2149
                    $source_file,
2150
                    $target_file,
2151
                    $password
2152
                );
2153
            } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) {
2154
                $err = "wrong_key";
2155
            } catch (Defuse\Crypto\Exception\EnvironmentIsBrokenException $ex) {
2156
                $err = $ex;
2157
            } catch (Defuse\Crypto\Exception\IOException $ex) {
2158
                $err = $ex;
2159
            }
2160
        }
2161
    }
2162
2163
    // return error
2164
    if (empty($err) === false) {
2165
        return $err;
2166
    } else {
2167
        return true;
0 ignored issues
show
Bug Best Practice introduced by
The expression return true returns the type true which is incompatible with the documented return type string.
Loading history...
2168
    }
2169
}
2170
2171
/*
2172
* NOT TO BE USED
2173
*/
2174
function debugTeampass($text)
2175
{
2176
    $debugFile = fopen('D:/wamp64/www/TeamPass/debug.txt', 'r+');
2177
    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

2177
    fputs(/** @scrutinizer ignore-type */ $debugFile, $text);
Loading history...
2178
    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

2178
    fclose(/** @scrutinizer ignore-type */ $debugFile);
Loading history...
2179
}
2180
2181
2182
/**
2183
 * DELETE the file with expected command depending on server type
2184
 * @param  string $file Path to file
2185
 * @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...
2186
 */
2187
function fileDelete($file)
2188
{
2189
    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...
2190
2191
    // Load AntiXSS
2192
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2193
    $antiXss = new protect\AntiXSS\AntiXSS();
2194
2195
    $file = $antiXss->xss_clean($file);
2196
    if (is_file($file)) {
2197
        unlink($file);
2198
    }
2199
}
2200
2201
/*
2202
* Permits to extract the file extension
2203
*/
2204
function getFileExtension($file)
2205
{
2206
    if (strpos($file, '.') === false) {
2207
        return $file;
2208
    }
2209
2210
    return substr($file, strrpos($file, '.') + 1);
2211
}
2212
2213
/**
2214
 * array_map
2215
 * @param  [type] $func [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
2216
 * @param  [type] $arr  [description]
2217
 * @return [type]       [description]
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
2218
 */
2219
function array_map_r($func, $arr)
2220
{
2221
    $newArr = array();
2222
2223
    foreach ($arr as $key => $value) {
2224
        $newArr[ $key ] = (is_array($value) ? array_map_r($func, $value) : ( is_array($func) ? call_user_func_array($func, $value) : $func( $value )));
2225
    }
2226
2227
    return $newArr;
2228
}
2229
2230
/**
2231
 * Permits to clean and sanitize text to be displayed
2232
 * @param  string $text text to clean
2233
 * @param  string $type what clean to perform
2234
 * @return string       text cleaned up
2235
 */
2236
function cleanText($string, $type = "")
2237
{
2238
    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...
2239
2240
    // Load AntiXSS
2241
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
2242
    $antiXss = new protect\AntiXSS\AntiXSS();
2243
2244
    if ($type === "css") {
2245
        // Escape text and quotes in UTF8 format
2246
        return htmlentities($string, ENT_QUOTES | ENT_HTML5, 'UTF-8');
2247
    } elseif ($type === "html" || empty($type)) {
2248
        // Html cleaner
2249
        return $antiXss->xss_clean($string);
0 ignored issues
show
Bug Best Practice introduced by
The expression return $antiXss->xss_clean($string) also could return the type array which is incompatible with the documented return type string.
Loading history...
2250
    }
2251
}
2252
2253
/**
2254
 * Performs chmod operation on subfolders
2255
 * @param  string  $dir             Parent folder
2256
 * @param  integer $dirPermissions  New permission on folders
2257
 * @param  integer $filePermissions New permission on files
2258
 * @return boolean                  Success/Failure
2259
 */
2260
function chmodRecursive($dir, $dirPermissions, $filePermissions)
2261
{
2262
    $pointer_dir = opendir($dir);
2263
    $res = true;
2264
    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

2264
    while ($file = readdir(/** @scrutinizer ignore-type */ $pointer_dir)) {
Loading history...
2265
        if (($file == ".") || ($file == "..")) {
2266
            continue;
2267
        }
2268
2269
        $fullPath = $dir."/".$file;
2270
2271
        if (is_dir($fullPath)) {
2272
            if ($res = @chmod($fullPath, $dirPermissions)) {
2273
                $res = @chmodRecursive($fullPath, $dirPermissions, $filePermissions);
2274
            }
2275
        } else {
2276
            $res = chmod($fullPath, $filePermissions);
2277
        }
2278
        if (!$res) {
2279
            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

2279
            closedir(/** @scrutinizer ignore-type */ $pointer_dir);
Loading history...
2280
            return false;
2281
        }
2282
    }
2283
    closedir($pointer_dir);
2284
    if (is_dir($dir) && $res) {
2285
        $res = @chmod($dir, $dirPermissions);
2286
    }
2287
2288
    return $res;
2289
}
2290
2291
/**
2292
 * Check if user can access to this item
2293
 * @param $item_id
2294
 */
2295
function accessToItemIsGranted($item_id)
2296
{
2297
    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...
2298
2299
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
2300
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
2301
2302
    // Prepare superGlobal variables
2303
    $session_groupes_visibles = $superGlobal->get("groupes_visibles", "SESSION");
2304
    $session_list_restricted_folders_for_items = $superGlobal->get("list_restricted_folders_for_items", "SESSION");
2305
2306
    // Load item data
2307
    $data = DB::queryFirstRow(
2308
        "SELECT id_tree
2309
        FROM ".prefix_table("items")."
2310
        WHERE id = %i",
2311
        $item_id
2312
    );
2313
2314
    // Check if user can access this folder
2315
    if (in_array($data['id_tree'], $session_groupes_visibles) === false) {
2316
        // Now check if this folder is restricted to user
2317
        if (isset($session_list_restricted_folders_for_items[$data['id_tree']])
2318
            && !in_array($item_id, $session_list_restricted_folders_for_items[$data['id_tree']])
2319
        ) {
2320
            return "ERR_FOLDER_NOT_ALLOWED";
2321
        } else {
2322
            return "ERR_FOLDER_NOT_ALLOWED";
2323
        }
2324
    }
2325
2326
    return true;
2327
}
2328
2329
/**
2330
 * Creates a unique key
2331
 * @lenght  integer $lenght key lenght
2332
 * @return string          key
2333
 */
2334
function uniqidReal($lenght = 13) {
2335
    // uniqid gives 13 chars, but you could adjust it to your needs.
2336
    if (function_exists("random_bytes")) {
2337
        $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

2337
        $bytes = random_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2338
    } elseif (function_exists("openssl_random_pseudo_bytes")) {
2339
        $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

2339
        $bytes = openssl_random_pseudo_bytes(/** @scrutinizer ignore-type */ ceil($lenght / 2));
Loading history...
2340
    } else {
2341
        throw new Exception("no cryptographically secure random function available");
2342
    }
2343
    return substr(bin2hex($bytes), 0, $lenght);
2344
}
2345
2346
/**
2347
 * Obfuscate an email address
2348
 * @email {string}  email address
2349
 */
2350
function obfuscate_email($email)
2351
{
2352
    $prop = 2;
2353
    $start = '';
2354
    $end = '';
2355
    $domain = substr(strrchr($email, "@"), 1);
2356
    $mailname = str_replace($domain, '', $email);
2357
    $name_l = strlen($mailname);
2358
    $domain_l = strlen($domain);
2359
    for($i = 0; $i <= $name_l/$prop-1; $i++) {
2360
        $start .= 'x';
2361
    }
2362
2363
    for($i = 0; $i <= $domain_l/$prop-1; $i++) {
2364
        $end .= 'x';
2365
    }
2366
2367
    return substr_replace($mailname, $start, 2, $name_l/$prop )
2368
        .substr_replace($domain, $end, 2, $domain_l/$prop); 
2369
}
2370
2371
/**
2372
 * Permits to get LDAP information about a user
2373
 *
2374
 * @param string $username  user name
2375
 * @param string $password  user password
2376
 * @return string
2377
 */
2378
function connectLDAP($username, $password, $SETTINGS) {
2379
    $user_email = '';
2380
    $user_found = false;
2381
    $user_lastname = '';
2382
    $user_name = '';
2383
    $ldapConnection = false;
2384
2385
    // Prepare LDAP connection if set up
2386
        //Multiple Domain Names
2387
    if (strpos(html_entity_decode($username), '\\') === true) {
2388
        $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...
2389
        $username = substr(html_entity_decode($username), strpos(html_entity_decode($username), '\\') + 1);
2390
    }
2391
    if ($SETTINGS['ldap_type'] === 'posix-search') {
2392
        $ldapURIs = "";
2393
        foreach (explode(",", $SETTINGS['ldap_domain_controler']) as $domainControler) {
2394
            if ($SETTINGS['ldap_ssl'] == 1) {
2395
                $ldapURIs .= "ldaps://".$domainControler.":".$SETTINGS['ldap_port']." ";
2396
            } else {
2397
                $ldapURIs .= "ldap://".$domainControler.":".$SETTINGS['ldap_port']." ";
2398
            }
2399
        }
2400
        $ldapconn = ldap_connect($ldapURIs);
2401
2402
        if ($SETTINGS['ldap_tls']) {
2403
            ldap_start_tls($ldapconn);
2404
        }
2405
        ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
2406
        ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
2407
2408
        // Is LDAP connection ready?
2409
        if ($ldapconn !== false) {
2410
            // Should we bind the connection?
2411
            if ($SETTINGS['ldap_bind_dn'] !== "" && $SETTINGS['ldap_bind_passwd'] !== "") {
2412
                $ldapbind = ldap_bind($ldapconn, $SETTINGS['ldap_bind_dn'], $SETTINGS['ldap_bind_passwd']);
2413
            } else {
2414
                $ldapbind = false;
2415
            }
2416
            if (($SETTINGS['ldap_bind_dn'] === "" && $SETTINGS['ldap_bind_passwd'] === "") || $ldapbind === true) {
2417
                $filter = "(&(".$SETTINGS['ldap_user_attribute']."=".$username.")(objectClass=".$SETTINGS['ldap_object_class']."))";
2418
                $result = ldap_search(
2419
                    $ldapconn,
2420
                    $SETTINGS['ldap_search_base'],
2421
                    $filter,
2422
                    array('dn', 'mail', 'givenname', 'sn', 'samaccountname')
2423
                );
2424
2425
                // Check if user was found in AD
2426
                if (ldap_count_entries($ldapconn, $result) > 0) {
2427
                    // Get user's info and especially the DN
2428
                    $result = ldap_get_entries($ldapconn, $result);
2429
                    $user_dn = $result[0]['dn'];
2430
                    $user_email = $result[0]['mail'][0];
2431
                    $user_lastname = $result[0]['sn'][0];
2432
                    $user_name = isset($result[0]['givenname'][0]) === true ? $result[0]['givenname'][0] : '';
2433
                    $user_found = true;
2434
2435
                    // Should we restrain the search in specified user groups
2436
                    $GroupRestrictionEnabled = false;
2437
                    if (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === false) {
2438
                        // New way to check User's group membership
2439
                        $filter_group = "memberUid=".$username;
2440
                        $result_group = ldap_search(
2441
                            $ldapconn,
2442
                            $SETTINGS['ldap_search_base'],
2443
                            $filter_group,
2444
                            array('dn', 'samaccountname')
2445
                        );
2446
2447
                        if ($result_group) {
0 ignored issues
show
introduced by
$result_group is of type resource, thus it always evaluated to false.
Loading history...
2448
                            $entries = ldap_get_entries($ldapconn, $result_group);
2449
2450
                            if ($entries['count'] > 0) {
2451
                                // Now check if group fits
2452
                                for ($i=0; $i<$entries['count']; $i++) {
2453
                                    $parsr=ldap_explode_dn($entries[$i]['dn'], 0);
2454
                                    if (str_replace(array('CN=','cn='), '', $parsr[0]) === $SETTINGS['ldap_usergroup']) {
2455
                                    $GroupRestrictionEnabled = true;
2456
                                    break;
2457
                                    }
2458
                                }
2459
2460
                            }
2461
                        }
2462
                    }
2463
2464
                    // Is user in the LDAP?
2465
                    if ($GroupRestrictionEnabled === true
2466
                        || (
2467
                            $GroupRestrictionEnabled === false
2468
                            && (isset($SETTINGS['ldap_usergroup']) === false
2469
                                || (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === true)
2470
                            )
2471
                        )
2472
                    ) {
2473
                        // Try to auth inside LDAP
2474
                        $ldapbind = ldap_bind($ldapconn, $user_dn, $password);
2475
                        if ($ldapbind === true) {
2476
                            $ldapConnection = true;
2477
2478
                        } else {
2479
                            $ldapConnection = false;
2480
                        }
2481
                    }
2482
                } else {
2483
                    $ldapConnection = false;
2484
                }
2485
            } else {
2486
                $ldapConnection = false;
2487
            }
2488
        } else {
2489
            $ldapConnection = false;
2490
        }
2491
    } else {
2492
        $adldap = new SplClassLoader('adLDAP', '../includes/libraries/LDAP');
2493
        $adldap->register();
2494
2495
        // Posix style LDAP handles user searches a bit differently
2496
        if ($SETTINGS['ldap_type'] === 'posix') {
2497
            $ldap_suffix = ','.$SETTINGS['ldap_suffix'].','.$SETTINGS['ldap_domain_dn'];
2498
        } else {
2499
            // 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...
2500
            //Multiple Domain Names
2501
            $ldap_suffix = $SETTINGS['ldap_suffix'];
2502
        }
2503
2504
        // Ensure no double commas exist in ldap_suffix
2505
        $ldap_suffix = str_replace(',,', ',', $ldap_suffix);
2506
2507
        // Create LDAP connection
2508
        $adldap = new adLDAP\adLDAP(
2509
            array(
2510
                'base_dn' => $SETTINGS['ldap_domain_dn'],
2511
                'account_suffix' => $ldap_suffix,
2512
                'domain_controllers' => explode(",", $SETTINGS['ldap_domain_controler']),
2513
                'ad_port' => $SETTINGS['ldap_port'],
2514
                'use_ssl' => $SETTINGS['ldap_ssl'],
2515
                'use_tls' => $SETTINGS['ldap_tls']
2516
            )
2517
        );
2518
2519
        // OpenLDAP expects an attribute=value pair
2520
        if ($SETTINGS['ldap_type'] === 'posix') {
2521
            $auth_username = $SETTINGS['ldap_user_attribute'].'='.$username;
2522
        } else {
2523
            $auth_username = $username;
2524
        }
2525
2526
        // Authenticate the user
2527
        if ($adldap->authenticate($auth_username, html_entity_decode($password))) {
2528
            // Get user info
2529
            $result = $adldap->user()->info($auth_username, array('mail', 'givenname', 'sn'));
2530
            $user_email = $result[0]['mail'][0];
2531
            $user_lastname = $result[0]['sn'][0];
2532
            $user_name = $result[0]['givenname'][0];
2533
            $user_found = true;
2534
2535
            // Is user in allowed group
2536
            if (isset($SETTINGS['ldap_allowed_usergroup']) === true
2537
                && empty($SETTINGS['ldap_allowed_usergroup']) === false
2538
            ) {
2539
                if ($adldap->user()->inGroup($auth_username, $SETTINGS['ldap_allowed_usergroup']) === true) {
2540
                    $ldapConnection = true;
2541
                } else {
2542
                    $ldapConnection = false;
2543
                }
2544
            } else {
2545
                $ldapConnection = true;
2546
            }
2547
        } else {
2548
            $ldapConnection = false;
2549
        }
2550
    }
2551
2552
    return json_encode(
2553
        array(
2554
            'lastname' => $user_lastname,
2555
            'name' => $user_name,
2556
            'email' => $user_email,
2557
            'auth_success' => $ldapConnection,
2558
            'user_found' => $user_found
2559
        )
2560
    );
2561
}
2562
2563