Passed
Branch development (e0e718)
by Nils
04:45
created

identify.php ➔ identifyUser()   F

Complexity

Conditions 187
Paths > 20000

Size

Total Lines 990
Code Lines 641

Duplication

Lines 71
Ratio 7.17 %

Importance

Changes 0
Metric Value
cc 187
eloc 641
nc 4294967295
nop 1
dl 71
loc 990
rs 2
c 0
b 0
f 0

How to fix   Long Method    Complexity   

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:

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

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

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

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

Loading history...
2
/**
3
 *
4
 * @file          identify.php
5
 * @author        Nils Laumaillé
6
 * @version       2.1.27
7
 * @copyright     (c) 2009-2017 Nils Laumaillé
8
 * @licensing     GNU GPL-3.0
9
 * @link          http://www.teampass.net
10
 *
11
 * This library is distributed in the hope that it will be useful,
12
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
 */
15
16
$debugLdap = 0; //Can be used in order to debug LDAP authentication
17
$debugDuo = 0; //Can be used in order to debug DUO authentication
18
19
require_once 'SecureHandler.php';
20
session_start();
21
if (!isset($_SESSION['CPM']) || $_SESSION['CPM'] !== 1) {
22
    die('Hacking attempt...');
23
}
24
25
// Load config
26
if (file_exists('../includes/config/tp.config.php')) {
27
    require_once '../includes/config/tp.config.php';
28
} elseif (file_exists('./includes/config/tp.config.php')) {
29
    require_once './includes/config/tp.config.php';
30
} else {
31
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
32
}
33
34
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir']) === true || $SETTINGS['cpassman_dir'] === ".") {
35
    $SETTINGS['cpassman_dir'] = "..";
36
}
37
38
// init
39
$dbgDuo = "";
40
$dbgLdap = "";
41
$ldap_suffix = "";
42
$result = "";
43
$adldap = "";
44
45
// Prepare POST variables
46
$post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
47
$post_login = filter_input(INPUT_POST, 'login', FILTER_SANITIZE_STRING);
48
$post_sig_response = filter_input(INPUT_POST, 'sig_response', FILTER_SANITIZE_STRING);
49
$post_cardid = filter_input(INPUT_POST, 'cardid', FILTER_SANITIZE_STRING);
50
$post_data = filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
51
$post_key = filter_input(INPUT_POST, 'key', FILTER_SANITIZE_STRING);
52
53
if ($post_type === "identify_duo_user") {
54
//--------
55
// DUO AUTHENTICATION
56
//--------
57
    // This step creates the DUO request encrypted key
58
59
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
60
    require_once SECUREPATH."/sk.php";
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...
61
62
    // load library
63
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/DuoSecurity/Duo.php';
64
    $sig_request = Duo::signRequest(IKEY, SKEY, AKEY, $post_login);
0 ignored issues
show
Bug introduced by
The constant SKEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant AKEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
Bug introduced by
The constant IKEY was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
65
66
    if ($debugDuo == 1) {
0 ignored issues
show
introduced by
The condition $debugDuo == 1 is always false.
Loading history...
67
        $dbgDuo = fopen($SETTINGS['path_to_files_folder']."/duo.debug.txt", "w");
68
        fputs(
69
            $dbgDuo,
70
            "\n\n-----\n\n".
71
            "sig request : ".$post_login."\n".
72
            'resp : '.$sig_request."\n"
73
        );
74
    }
75
76
    // load csrfprotector
77
    $csrfp_config = require_once $SETTINGS['cpassman_dir'].'/includes/libraries/csrfp/libs/csrfp.config.php';
78
79
    // return result
80
    echo '[{"sig_request" : "'.$sig_request.'" , "csrfp_token" : "'.$csrfp_config['CSRFP_TOKEN'].'" , "csrfp_key" : "'.filter_var($_COOKIE[$csrfp_config['CSRFP_TOKEN']], FILTER_SANITIZE_STRING).'"}]';
81
// DUO Identification
82
} elseif ($post_type === "identify_duo_user_check") {
83
//--------
84
// DUO AUTHENTICATION
85
// this step is verifying the response received from the server
86
//--------
87
88
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
89
    require_once SECUREPATH."/sk.php";
90
91
    // load library
92
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/DuoSecurity/Duo.php';
93
    $resp = Duo::verifyResponse(IKEY, SKEY, AKEY, $post_sig_response);
94
95
    if ($debugDuo == 1) {
0 ignored issues
show
introduced by
The condition $debugDuo == 1 is always false.
Loading history...
96
        $dbgDuo = fopen($SETTINGS['path_to_files_folder']."/duo.debug.txt", "a");
97
        fputs(
98
            $dbgDuo,
99
            "\n\n-----\n\n".
100
            "sig response : ".$post_sig_response."\n".
101
            'resp : '.$resp."\n"
102
        );
103
    }
104
105
    // return the response (which should be the user name)
106
    if ($resp === $post_login) {
107
        echo '[{"resp" : "'.$resp.'"}]';
108
    } else {
109
        echo '[{"resp" : "'.$resp.'"}]';
110
    }
111
} elseif ($post_type === "identify_user_with_agses") {
112
//--------
113
//-- AUTHENTICATION WITH AGSES
114
//--------
115
116
    require_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
117
    require_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
118
    // connect to the server
119
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
120
    $pass = defuse_return_decrypted($pass);
121
    DB::$host = $server;
122
    DB::$user = $user;
123
    DB::$password = $pass;
124
    DB::$dbName = $database;
125
    DB::$port = $port;
126
    DB::$encoding = $encoding;
127
    DB::$error_handler = true;
128
    $link = mysqli_connect($server, $user, $pass, $database, $port);
129
    $link->set_charset($encoding);
130
131
    // do checks
132
    if (null !== $post_cardid && empty(post_cardid) === true) {
0 ignored issues
show
Bug introduced by
The constant post_cardid was not found. Maybe you did not declare it correctly or list all dependencies?
Loading history...
133
        // no card id is given
134
        // check if it is DB
135
        $row = DB::queryFirstRow(
136
            "SELECT `agses-usercardid` FROM ".prefix_table("users")."
137
            WHERE login = %s",
138
            $post_login
139
        );
140
    } elseif (empty($post_cardid) === false && is_numeric($post_cardid)) {
141
        // card id is given
142
        // save it in DB
143
        DB::update(
144
            prefix_table('users'),
145
            array(
146
                'agses-usercardid' => $post_cardid
147
                ),
148
            "login = %s",
149
            $post_login
150
        );
151
        $row['agses-usercardid'] = $post_cardid;
152
    } else {
153
        // error
154
        echo '[{"error" : "something_wrong" , "agses_message" : ""}]';
155
        return false;
156
    }
157
158
    //-- get AGSES hosted information
159
    $ret_agses_url = DB::queryFirstRow(
160
        "SELECT valeur FROM ".prefix_table("misc")."
161
        WHERE type = %s AND intitule = %s",
162
        'admin',
163
        'agses_hosted_url'
164
    );
165
166
    $ret_agses_id = DB::queryFirstRow(
167
        "SELECT valeur FROM ".prefix_table("misc")."
168
        WHERE type = %s AND intitule = %s",
169
        'admin',
170
        'agses_hosted_id'
171
    );
172
173
    $ret_agses_apikey = DB::queryFirstRow(
174
        "SELECT valeur FROM ".prefix_table("misc")."
175
        WHERE type = %s AND intitule = %s",
176
        'admin',
177
        'agses_hosted_apikey'
178
    );
179
180
    // if we have a card id and all agses credentials
181
    // then we try to generate the message for agsesflicker
182
    if (isset($row['agses-usercardid']) && empty($ret_agses_url['valeur']) === false
183
        && empty($ret_agses_id['valeur']) === false && empty($ret_agses_apikey['valeur']) === false
184
    ) {
185
        // check that card id is not empty or equal to 0
186
        if ($row['agses-usercardid'] !== "0" && !empty($row['agses-usercardid'])) {
187
            include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/agses/axs/AXSILPortal_V1_Auth.php';
188
            $agses = new AXSILPortal_V1_Auth();
189
            $agses->setUrl($ret_agses_url['valeur']);
190
            $agses->setAAId($ret_agses_id['valeur']);
191
            //for release there will be another api-key - this is temporary only
192
            $agses->setApiKey($ret_agses_apikey['valeur']);
193
            $agses->create();
194
            //create random salt and store it into session
195
            if (!isset($_SESSION['hedgeId']) || empty($_SESSION['hedgeId']) === true) {
196
                $_SESSION['hedgeId'] = md5(time());
197
            }
198
            $_SESSION['user_settings']['agses-usercardid'] = $row['agses-usercardid'];
199
            $agses_message = $agses->createAuthenticationMessage(
200
                (string) $row['agses-usercardid'],
201
                true,
202
                1,
203
                2,
204
                (string) $_SESSION['hedgeId']
205
            );
206
207
            echo '[{"agses_message" : "'.$agses_message.'" , "error" : ""}]';
208
        } else {
209
            echo '[{"agses_status" : "no_user_card_id" , "agses_message" : "" , "error" : ""}]';
210
        }
211
    } else {
212
        if (empty($ret_agses_apikey['valeur']) || empty($ret_agses_url['valeur']) || empty($ret_agses_id['valeur'])) {
213
            echo '[{"error" : "no_agses_info" , "agses_message" : ""}]';
214
        } else {
215
            echo '[{"error" : "something_wrong" , "agses_message" : ""}]'; // user not found but not displayed as this in the error message
216
        }
217
    }
218
} elseif ($post_type === "identify_user") {
219
//--------
220
// NORMAL IDENTICATION STEP
221
//--------
222
223
    // increment counter of login attempts
224
    if (empty($_SESSION["pwd_attempts"])) {
225
        $_SESSION["pwd_attempts"] = 1;
226
    } else {
227
        $_SESSION["pwd_attempts"]++;
228
    }
229
230
    // manage brute force
231
    if ($_SESSION["pwd_attempts"] <= 3) {
232
        // identify the user through Teampass process
233
        identifyUser($post_data);
234
    } elseif (isset($_SESSION["next_possible_pwd_attempts"]) && time() > $_SESSION["next_possible_pwd_attempts"] && $_SESSION["pwd_attempts"] > 3) {
235
        $_SESSION["pwd_attempts"] = 1;
236
        // identify the user through Teampass process
237
        identifyUser($post_data);
238
    } else {
239
        $_SESSION["next_possible_pwd_attempts"] = time() + 10;
240
        echo '[{"error" : "bruteforce_wait"}]';
241
        return false;
242
    }
243
} elseif ($post_type === "store_data_in_cookie") {
244
//--------
245
// STORE DATA IN COOKIE
246
//--------
247
//
248
    // not used any more (only development purpose)
249
    if ($post_key !== $_SESSION['key']) {
250
        echo '[{"error" : "something_wrong"}]';
251
        return false;
252
    }
253
    // store some connection data in cookie
254
    setcookie(
255
        "TeamPassC",
256
        $post_data,
257
        time() + 60 * 60,
258
        '/'
259
    );
260
}
261
262
/*
263
* Complete authentication of user through Teampass
264
*/
265
function identifyUser($sentData)
266
{
267
    global $debugLdap, $debugDuo, $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...
268
269
    // Load config
270
    if (file_exists('../includes/config/tp.config.php')) {
271
        require_once '../includes/config/tp.config.php';
272
    } elseif (file_exists('./includes/config/tp.config.php')) {
273
        require_once './includes/config/tp.config.php';
274
    } else {
275
        throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
276
    }
277
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
278
279
    header("Content-type: text/html; charset=utf-8");
280
    error_reporting(E_ERROR);
281
    require_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
282
    require_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
283
284
    // Load AntiXSS
285
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
286
    $antiXss = new protect\AntiXSS\AntiXSS();
287
288
    if ($debugDuo == 1) {
289
        $dbgDuo = fopen($SETTINGS['path_to_files_folder']."/duo.debug.txt", "a");
290
    }
291
292
    if ($debugDuo == 1) {
293
        fputs(
294
            $dbgDuo,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dbgDuo does not seem to be defined for all execution paths leading up to this point.
Loading history...
295
            "Content of data sent '".filter_var($sentData, FILTER_SANITIZE_STRING)."'\n"
296
        );
297
    }
298
299
    // connect to the server
300
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
301
    $pass = defuse_return_decrypted($pass);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pass seems to be never defined.
Loading history...
302
    DB::$host = $server;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $server seems to be never defined.
Loading history...
303
    DB::$user = $user;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $user does not exist. Did you maybe mean $user_dn?
Loading history...
304
    DB::$password = $pass;
305
    DB::$dbName = $database;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $database seems to be never defined.
Loading history...
306
    DB::$port = $port;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $port seems to be never defined.
Loading history...
307
    DB::$encoding = $encoding;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $encoding seems to be never defined.
Loading history...
308
    DB::$error_handler = true;
309
    $link = mysqli_connect($server, $user, $pass, $database, $port);
310
    $link->set_charset($encoding);
311
312
    // load passwordLib library
313
    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'].'/includes/libraries');
314
    $pwdlib->register();
315
    $pwdlib = new PasswordLib\PasswordLib();
316
317
    // User's language loading
318
    require_once $SETTINGS['cpassman_dir'].'/includes/language/'.$_SESSION['user_language'].'.php';
319
320
    // decrypt and retreive data in JSON format
321
    $dataReceived = prepareExchangedData($sentData, "decode");
322
323
    // prepare variables
324
	if (isset($SETTINGS['enable_http_request_login']) === true
325
        && $SETTINGS['enable_http_request_login'] === '1'
326
        && isset($_SERVER['PHP_AUTH_USER']) === true
327
        && !(isset($SETTINGS['maintenance_mode']) === true
328
        && $SETTINGS['maintenance_mode'] === '1')
329
    ) {
330
        if (strpos($_SERVER['PHP_AUTH_USER'], '@') !== false) {
331
			$username = explode("@", $_SERVER['PHP_AUTH_USER'])[0];
332
		} elseif (strpos($_SERVER['PHP_AUTH_USER'], '\\') !== false) {
333
			$username = explode("\\", $_SERVER['PHP_AUTH_USER'])[1];
334
		} else {
335
			$username = $_SERVER['PHP_AUTH_USER'];
336
		}
337
		$passwordClear = $_SERVER['PHP_AUTH_PW'];
338
		$pwdOldEncryption = encryptOld($_SERVER['PHP_AUTH_PW']);
0 ignored issues
show
Unused Code introduced by
The assignment to $pwdOldEncryption is dead and can be removed.
Loading history...
339
	}else{
340
		$passwordClear = htmlspecialchars_decode($dataReceived['pw']);
341
		$pwdOldEncryption = encryptOld(htmlspecialchars_decode($dataReceived['pw']));
342
		$username = $antiXss->xss_clean(htmlspecialchars_decode($dataReceived['login']));
343
	}
344
    $logError = "";
345
    $userPasswordVerified = false;
346
347
    if ($debugDuo == 1) {
348
        fputs(
349
            $dbgDuo,
350
            "Starting authentication of '".$username."'\n"
0 ignored issues
show
Security File Manipulation introduced by
'Starting authentication of '' . $username . '' ' can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username in sources/identify.php on line 335
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 335
  2. Path: Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username in sources/identify.php on line 333
  1. Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username
    in sources/identify.php on line 333
  3. Path: Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username in sources/identify.php on line 331
  1. Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username
    in sources/identify.php on line 331

General Strategies to prevent injection

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

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

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

$sanitized = (integer) $tainted;
Loading history...
351
        );
352
    }
353
354
    $ldapConnection = false;
355
356
    /* LDAP connection */
357
    if ($debugLdap == 1) {
358
        // create temp file
359
        $dbgLdap = fopen($SETTINGS['path_to_files_folder']."/ldap.debug.txt", "w");
360
        fputs(
361
            $dbgLdap,
0 ignored issues
show
Bug introduced by
It seems like $dbgLdap 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

361
            /** @scrutinizer ignore-type */ $dbgLdap,
Loading history...
362
            "Get all LDAP params : \n".
363
            'mode : '.$SETTINGS['ldap_mode']."\n".
364
            'type : '.$SETTINGS['ldap_type']."\n".
365
            'base_dn : '.$SETTINGS['ldap_domain_dn']."\n".
366
            'search_base : '.$SETTINGS['ldap_search_base']."\n".
367
            'bind_dn : '.$SETTINGS['ldap_bind_dn']."\n".
368
            'bind_passwd : '.$SETTINGS['ldap_bind_passwd']."\n".
369
            'user_attribute : '.$SETTINGS['ldap_user_attribute']."\n".
370
            'account_suffix : '.$SETTINGS['ldap_suffix']."\n".
371
            'domain_controllers : '.$SETTINGS['ldap_domain_controler']."\n".
372
            'ad_port : '.$SETTINGS['ldap_port']."\n".
373
            'use_ssl : '.$SETTINGS['ldap_ssl']."\n".
374
            'use_tls : '.$SETTINGS['ldap_tls']."\n*********\n\n"
375
        );
376
    }
377
378
    if ($debugDuo == 1) {
379
        fputs(
380
            $dbgDuo,
381
            "LDAP status: ".$SETTINGS['ldap_mode']."\n"
382
        );
383
    }
384
385
    // Check if user exists
386
    $data = DB::queryFirstRow(
387
        "SELECT * FROM ".prefix_table("users")." WHERE login=%s_login",
388
        array(
389
            'login' => $username
390
        )
391
    );
392
    $counter = DB::count();
393
    $user_initial_creation_through_ldap = false;
394
    $proceedIdentification = false;
395
396
    // Prepare LDAP connection if set up
397
    if (isset($SETTINGS['ldap_mode'])
398
        && $SETTINGS['ldap_mode'] === '1'
399
        && $username !== "admin"
400
    ) {
401
        //Multiple Domain Names
402
        if (strpos(html_entity_decode($username), '\\') === true) {
403
            $ldap_suffix = "@".substr(html_entity_decode($username), 0, strpos(html_entity_decode($username), '\\'));
404
            $username = substr(html_entity_decode($username), strpos(html_entity_decode($username), '\\') + 1);
405
        }
406
        if ($SETTINGS['ldap_type'] === 'posix-search') {
407
            $ldapURIs = "";
408
            foreach (explode(",", $SETTINGS['ldap_domain_controler']) as $domainControler) {
409
                if ($SETTINGS['ldap_ssl'] == 1) {
410
                    $ldapURIs .= "ldaps://".$domainControler.":".$SETTINGS['ldap_port']." ";
411
                } else {
412
                    $ldapURIs .= "ldap://".$domainControler.":".$SETTINGS['ldap_port']." ";
413
                }
414
            }
415
            if ($debugLdap == 1) {
416
                fputs($dbgLdap, "LDAP URIs : ".$ldapURIs."\n");
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dbgLdap does not seem to be defined for all execution paths leading up to this point.
Loading history...
417
            }
418
            $ldapconn = ldap_connect($ldapURIs);
419
420
            if ($SETTINGS['ldap_tls']) {
421
                ldap_start_tls($ldapconn);
422
            }
423
            if ($debugLdap == 1) {
424
                fputs($dbgLdap, "LDAP connection : ".($ldapconn ? "Connected" : "Failed")."\n");
0 ignored issues
show
introduced by
The condition $ldapconn is always false.
Loading history...
425
            }
426
            ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
427
            ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
428
429
            // Is LDAP connection ready?
430
            if ($ldapconn !== false) {
431
                // Should we bind the connection?
432
                if ($SETTINGS['ldap_bind_dn'] !== "" && $SETTINGS['ldap_bind_passwd'] !== "") {
433
                    $ldapbind = ldap_bind($ldapconn, $SETTINGS['ldap_bind_dn'], $SETTINGS['ldap_bind_passwd']);
434
                    if ($debugLdap == 1) {
435
                        fputs($dbgLdap, "LDAP bind : ".($ldapbind ? "Bound" : "Failed")."\n");
436
                    }
437
                }
438
                if (($SETTINGS['ldap_bind_dn'] === "" && $SETTINGS['ldap_bind_passwd'] === "") || $ldapbind === true) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ldapbind does not seem to be defined for all execution paths leading up to this point.
Loading history...
439
                    $filter = "(&(".$SETTINGS['ldap_user_attribute']."=".$username.")(objectClass=".$SETTINGS['ldap_object_class']."))";
440
                    $result = ldap_search(
441
                      $ldapconn,
442
                      $SETTINGS['ldap_search_base'],
443
                      $filter,
0 ignored issues
show
Security LDAP Injection introduced by
$filter can contain request data and is used in ldap context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username in sources/identify.php on line 335
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 335
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 439
  2. Path: Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username in sources/identify.php on line 333
  1. Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username
    in sources/identify.php on line 333
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 439
  3. Path: Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username in sources/identify.php on line 331
  1. Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username
    in sources/identify.php on line 331
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 439

General Strategies to prevent injection

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

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

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

$sanitized = (integer) $tainted;
Loading history...
444
                      array('dn', 'mail', 'givenname', 'sn')
445
                    );
446
                    if ($debugLdap == 1) {
447
                        fputs(
448
                            $dbgLdap,
449
                            'Search filter : '.$filter."\n".
0 ignored issues
show
Security File Manipulation introduced by
'Search filter : ' . $fi..., $result), true) . ' ' can contain request data and is used in file manipulation context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username in sources/identify.php on line 335
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 335
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 439
  2. Path: Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username in sources/identify.php on line 333
  1. Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username
    in sources/identify.php on line 333
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 439
  3. Path: Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username in sources/identify.php on line 331
  1. Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username
    in sources/identify.php on line 331
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 439

General Strategies to prevent injection

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

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

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

$sanitized = (integer) $tainted;
Loading history...
450
                            'Results : '.print_r(ldap_get_entries($ldapconn, $result), true)."\n"
451
                        );
452
                    }
453
454
                    // Check if user was found in AD
455
                    if (ldap_count_entries($ldapconn, $result) > 0) {
456
                        // Get user's info and especially the DN
457
                        $result = ldap_get_entries($ldapconn, $result);
458
                        $user_dn = $result[0]['dn'];
459
460
                        fputs(
461
                            $dbgLdap,
462
                            'User was found. '.$user_dn.'\n'
463
                        );
464
465
                        // Should we restrain the search in specified user groups
466
                        $GroupRestrictionEnabled = false;
467
                        if (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === false) {
468
                            // New way to check User's group membership
469
                            $filter_group = "memberUid=".$username;
470
                            $result_group = ldap_search(
471
                                $ldapconn,
472
                                $SETTINGS['ldap_search_base'],
473
                                $filter_group,
0 ignored issues
show
Security LDAP Injection introduced by
$filter_group can contain request data and is used in ldap context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username in sources/identify.php on line 335
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 335
  2. 'memberUid=' . $username is assigned to $filter_group
    in sources/identify.php on line 469
  2. Path: Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username in sources/identify.php on line 333
  1. Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username
    in sources/identify.php on line 333
  2. 'memberUid=' . $username is assigned to $filter_group
    in sources/identify.php on line 469
  3. Path: Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username in sources/identify.php on line 331
  1. Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username
    in sources/identify.php on line 331
  2. 'memberUid=' . $username is assigned to $filter_group
    in sources/identify.php on line 469

General Strategies to prevent injection

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

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

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

$sanitized = (integer) $tainted;
Loading history...
474
                                array('dn')
475
                            );
476
477
                            if ($result_group) {
0 ignored issues
show
introduced by
The condition $result_group is always false.
Loading history...
478
                                $entries = ldap_get_entries($ldapconn, $result_group);
479
480
                                if ($debugLdap == 1) {
481
                                    fputs(
482
                                        $dbgLdap,
483
                                        'Search groups appartenance : '.$SETTINGS['ldap_search_base']."\n".
484
                                        'Results : '.print_r($entries, true)."\n"
485
                                    );
486
                                }
487
488
                                if ($entries['count'] > 0) {
489
                                    // Now check if group fits
490
                                    for ($i=0; $i<$entries['count']; $i++) {
491
                                      $parsr=ldap_explode_dn($entries[$i]['dn'], 0);
492
                                      if (str_replace(array('CN=','cn='), '', $parsr[0]) === $SETTINGS['ldap_usergroup']) {
493
                                        $GroupRestrictionEnabled = true;
494
                                        break;
495
                                      }
496
                                    }
497
498
                                }
499
                            }
500
501
                            if ($debugLdap == 1) {
502
                                fputs(
503
                                    $dbgLdap,
504
                                    'Group was found : '.$GroupRestrictionEnabled."\n"
0 ignored issues
show
Bug introduced by
Are you sure $GroupRestrictionEnabled of type false can be used in concatenation? ( Ignorable by Annotation )

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

504
                                    'Group was found : './** @scrutinizer ignore-type */ $GroupRestrictionEnabled."\n"
Loading history...
505
                                );
506
                            }
507
                        }
508
509
                        // Is user in the LDAP?
510
                        if ($GroupRestrictionEnabled === true
511
                            || (
512
                                $GroupRestrictionEnabled === false
513
                                && (isset($SETTINGS['ldap_usergroup']) === false
514
                                    || (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === true)
515
                                )
516
                            )
517
                        ) {
518
                            // Try to auth inside LDAP
519
                            $ldapbind = ldap_bind($ldapconn, $user_dn, $passwordClear);
520
                            if ($ldapbind === true) {
521
                                $ldapConnection = true;
522
523
                                // Update user's password
524
                                $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
525
526
                                // Do things if user exists in TP
527
                                if ($counter > 0) {
528
                                    // Update pwd in TP database
529
                                    DB::update(
530
                                        prefix_table('users'),
531
                                        array(
532
                                            'pw' => $data['pw']
533
                                        ),
534
                                        "login=%s",
535
                                        $username
536
                                    );
537
538
                                    // No user creation is requested
539
                                    $proceedIdentification = true;
540
                                }
541
                            } else {
542
                                $ldapConnection = false;
543
                            }
544
                        }
545
                    } else {
546
                        $ldapConnection = false;
547
                    }
548
                } else {
549
                    $ldapConnection = false;
550
                }
551
            } else {
552
                $ldapConnection = false;
553
            }
554
        } else {
555
            if ($debugLdap == 1) {
556
                fputs(
557
                    $dbgLdap,
558
                    "Get all ldap params : \n".
559
                    'base_dn : '.$SETTINGS['ldap_domain_dn']."\n".
560
                    'account_suffix : '.$SETTINGS['ldap_suffix']."\n".
561
                    'domain_controllers : '.$SETTINGS['ldap_domain_controler']."\n".
562
                    'ad_port : '.$SETTINGS['ldap_port']."\n".
563
                    'use_ssl : '.$SETTINGS['ldap_ssl']."\n".
564
                    'use_tls : '.$SETTINGS['ldap_tls']."\n*********\n\n"
565
                );
566
            }
567
            $adldap = new SplClassLoader('adLDAP', '../includes/libraries/LDAP');
568
            $adldap->register();
569
570
            // Posix style LDAP handles user searches a bit differently
571
            if ($SETTINGS['ldap_type'] === 'posix') {
572
                $ldap_suffix = ','.$SETTINGS['ldap_suffix'].','.$SETTINGS['ldap_domain_dn'];
573
            } elseif ($SETTINGS['ldap_type'] === 'windows' && empty($ldap_suffix) === true) {
574
                //Multiple Domain Names
575
                $ldap_suffix = $SETTINGS['ldap_suffix'];
576
            }
577
578
            // Ensure no double commas exist in ldap_suffix
579
            $ldap_suffix = str_replace(',,', ',', $ldap_suffix);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ldap_suffix does not seem to be defined for all execution paths leading up to this point.
Loading history...
580
581
            // Create LDAP connection
582
            $adldap = new adLDAP\adLDAP(
583
                array(
584
                    'base_dn' => $SETTINGS['ldap_domain_dn'],
585
                    'account_suffix' => $ldap_suffix,
586
                    'domain_controllers' => explode(",", $SETTINGS['ldap_domain_controler']),
587
                    'ad_port' => $SETTINGS['ldap_port'],
588
                    'use_ssl' => $SETTINGS['ldap_ssl'],
589
                    'use_tls' => $SETTINGS['ldap_tls']
590
                )
591
            );
592
593
            if ($debugLdap == 1) {
594
                fputs($dbgLdap, "Create new adldap object : ".$adldap->getLastError()."\n\n\n"); //Debug
595
            }
596
597
            // OpenLDAP expects an attribute=value pair
598
            if ($SETTINGS['ldap_type'] === 'posix') {
599
                $auth_username = $SETTINGS['ldap_user_attribute'].'='.$username;
600
            } else {
601
                $auth_username = $username;
602
            }
603
604
            // Authenticate the user
605
            if ($adldap->authenticate($auth_username, html_entity_decode($passwordClear))) {
606
                // Is user in allowed group
607
                if (isset($SETTINGS['ldap_allowed_usergroup']) === true
608
                    && empty($SETTINGS['ldap_allowed_usergroup']) === false
609
                ) {
610
                    if ($adldap->user()->inGroup($auth_username, $SETTINGS['ldap_allowed_usergroup']) === true) {
611
                        $ldapConnection = true;
612
                    } else {
613
                        $ldapConnection = false;
614
                    }
615
                } else {
616
                    $ldapConnection = true;
617
                }
618
619
                // Update user's password
620
                if ($ldapConnection === true) {
621
                    $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
622
623
                    // Do things if user exists in TP
624
                    if ($counter > 0) {
625
                        // Update pwd in TP database
626
                        DB::update(
627
                            prefix_table('users'),
628
                            array(
629
                                'pw' => $data['pw']
630
                            ),
631
                            "login=%s",
632
                            $username
633
                        );
634
635
                        // No user creation is requested
636
                        $proceedIdentification = true;
637
                    }
638
                }
639
            } else {
640
                $ldapConnection = false;
641
            }
642
            if ($debugLdap == 1) {
643
                fputs(
644
                    $dbgLdap,
645
                    "After authenticate : ".$adldap->getLastError()."\n\n\n".
646
                    "ldap status : ".$ldapConnection."\n\n\n"
647
                ); //Debug
648
            }
649
        }
650
    } elseif (isset($SETTINGS['ldap_mode']) && $SETTINGS['ldap_mode'] == 2) {
0 ignored issues
show
Unused Code introduced by
This elseif statement is empty, and could be removed.

This check looks for the bodies of elseif statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These elseif bodies can be removed. If you have an empty elseif but statements in the else branch, consider inverting the condition.

Loading history...
651
        // nothing
652
    }
653
    if ($debugDuo == 1) {
654
        fputs(
655
            $dbgDuo,
656
            "USer exists: ".$counter."\n"
657
        );
658
    }
659
660
661
    // Check PSK
662
    if (isset($SETTINGS['psk_authentication'])
663
        && $SETTINGS['psk_authentication'] === "1"
664
        && $data['admin'] !== "1"
665
    ) {
666
        $psk = htmlspecialchars_decode($dataReceived['psk']);
667
        $pskConfirm = htmlspecialchars_decode($dataReceived['psk_confirm']);
668
        if (empty($psk)) {
669
            echo '[{"value" : "psk_required"}]';
670
            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...
671
        } elseif (empty($data['psk'])) {
672
            if (empty($pskConfirm)) {
673
                echo '[{"value" : "bad_psk_confirmation"}]';
674
                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...
675
            } else {
676
                $_SESSION['user_settings']['clear_psk'] = $psk;
677
            }
678
        } elseif ($pwdlib->verifyPasswordHash($psk, $data['psk']) === true) {
679
            echo '[{"value" : "bad_psk"}]';
680
            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...
681
        }
682
    }
683
684
685
    // Create new LDAP user if not existing in Teampass
686
    // Don't create it if option "only localy declared users" is enabled
687
    if ($counter == 0 && $ldapConnection === true && isset($SETTINGS['ldap_elusers'])
688
        && ($SETTINGS['ldap_elusers'] == 0)
689
    ) {
690
        // If LDAP enabled, create user in TEAMPASS if doesn't exist
691
692
        // Get user info from LDAP
693
        if ($SETTINGS['ldap_type'] === 'posix-search') {
694
            //Because we didn't use adLDAP, we need to set the user info from the ldap_get_entries result
695
            $user_info_from_ad = $result;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $result does not seem to be defined for all execution paths leading up to this point.
Loading history...
696
        } else {
697
            $user_info_from_ad = $adldap->user()->info($auth_username, array("mail", "givenname", "sn"));
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $adldap does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $auth_username does not seem to be defined for all execution paths leading up to this point.
Loading history...
698
        }
699
700
        DB::insert(
701
            prefix_table('users'),
702
            array(
703
                'login' => $username,
704
                'pw' => $data['pw'],
705
                'email' => (isset($user_info_from_ad[0]['mail'][0]) === false) ? '' : $user_info_from_ad[0]['mail'][0],
706
                'name' => $user_info_from_ad[0]['givenname'][0],
707
                'lastname' => $user_info_from_ad[0]['sn'][0],
708
                'admin' => '0',
709
                'gestionnaire' => '0',
710
                'can_manage_all_users' => '0',
711
                'personal_folder' => $SETTINGS['enable_pf_feature'] === "1" ? '1' : '0',
712
                'fonction_id' => isset($SETTINGS['ldap_new_user_role']) === true ? $SETTINGS['ldap_new_user_role'] : '0',
713
                'groupes_interdits' => '',
714
                'groupes_visibles' => '',
715
                'last_pw_change' => time(),
716
                'user_language' => $SETTINGS['default_language'],
717
                'encrypted_psk' => '',
718
                'isAdministratedByRole' => (isset($SETTINGS['ldap_new_user_is_administrated_by']) === true && empty($SETTINGS['ldap_new_user_is_administrated_by']) === false) ? $SETTINGS['ldap_new_user_is_administrated_by'] : 0
719
            )
720
        );
721
        $newUserId = DB::insertId();
722
        // Create personnal folder
723
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === "1") {
724
            DB::insert(
725
                prefix_table("nested_tree"),
726
                array(
727
                    'parent_id' => '0',
728
                    'title' => $newUserId,
729
                    'bloquer_creation' => '0',
730
                    'bloquer_modification' => '0',
731
                    'personal_folder' => '1'
732
                )
733
            );
734
        }
735
        $proceedIdentification = true;
736
        $user_initial_creation_through_ldap = true;
737
    }
738
739
    // Check if user exists (and has been created in case of new LDAP user)
740
    $data = DB::queryFirstRow(
741
        "SELECT * FROM ".prefix_table("users")." WHERE login=%s_login",
742
        array(
743
            'login' => $username
744
        )
745
    );
746
    $counter = DB::count();
747
    if ($counter === 0) {
748
        logEvents('failed_auth', 'user_not_exists', "", stripslashes($username));
749
        echo '[{"value" : "user_not_exists '.$username.'", "text":""}]';
0 ignored issues
show
Security Cross-Site Scripting introduced by
'[{"value" : "user_not_e...name . '", "text":""}]' can contain request data and is used in output context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username in sources/identify.php on line 335
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 335
  2. Path: Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username in sources/identify.php on line 333
  1. Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username
    in sources/identify.php on line 333
  3. Path: Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username in sources/identify.php on line 331
  1. Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username
    in sources/identify.php on line 331

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

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

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

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

$sanitized = (integer) $tainted;
Loading history...
750
        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...
751
    }
752
753
    // check GA code
754
    if (isset($SETTINGS['google_authentication']) && $SETTINGS['google_authentication'] == 1 && $username !== "admin") {
755
        if (isset($dataReceived['GACode']) && empty($dataReceived['GACode']) === false) {
756
            // load library
757
            include_once($SETTINGS['cpassman_dir']."/includes/libraries/Authentication/TwoFactorAuth/TwoFactorAuth.php");
758
759
            // create new instance
760
            $tfa = new Authentication\TwoFactorAuth\TwoFactorAuth($SETTINGS['ga_website_name']);
761
762
            // now check if it is the 1st time the user is using 2FA
763
            if ($data['ga_temporary_code'] !== "none" && $data['ga_temporary_code'] !== "done") {
764
                if ($data['ga_temporary_code'] !== $dataReceived['GACode']) {
765
                    $proceedIdentification = false;
766
                    $logError = "ga_temporary_code_wrong";
767
                } else {
768
                    $proceedIdentification = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $proceedIdentification is dead and can be removed.
Loading history...
769
                    $logError = "ga_temporary_code_correct";
770
771
                    // generate new QR
772
                    $new_2fa_qr = $tfa->getQRCodeImageAsDataUri("Teampass - ".$username, $data['ga']);
773
774
                    // clear temporary code from DB
775
                    DB::update(
776
                        prefix_table('users'),
777
                        array(
778
                            'ga_temporary_code' => 'done'
779
                        ),
780
                        "id=%i",
781
                        $data['id']
782
                    );
783
784
                    echo '[{"value" : "<img src=\"'.$new_2fa_qr.'\">", "user_admin":"', isset($_SESSION['user_admin']) ? $antiXss->xss_clean($_SESSION['user_admin']) : "", '", "initial_url" : "'.@$_SESSION['initial_url'].'", "error" : "'.$logError.'"}]';
0 ignored issues
show
Bug introduced by
Are you sure IssetNode ? $antiXss->xs...ION['user_admin']) : '' of type string|array can be used in echo? ( Ignorable by Annotation )

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

784
                    echo '[{"value" : "<img src=\"'.$new_2fa_qr.'\">", "user_admin":"', /** @scrutinizer ignore-type */ isset($_SESSION['user_admin']) ? $antiXss->xss_clean($_SESSION['user_admin']) : "", '", "initial_url" : "'.@$_SESSION['initial_url'].'", "error" : "'.$logError.'"}]';
Loading history...
785
786
                    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...
787
                }
788
            } else {
789
                // verify the user GA code
790
                if ($tfa->verifyCode($data['ga'], $dataReceived['GACode'])) {
791
                    $proceedIdentification = true;
792
                } else {
793
                    $proceedIdentification = false;
794
                    $logError = "ga_code_wrong";
795
                }
796
            }
797
        } else {
798
            $proceedIdentification = false;
799
            $logError = "ga_code_wrong";
800
        }
801
    } elseif ($counter > 0) {
802
        $proceedIdentification = true;
803
    }
804
805
    if ($debugDuo == 1) {
806
        fputs(
807
            $dbgDuo,
808
            "Proceed with Ident: ".$proceedIdentification."\n"
809
        );
810
    }
811
812
813
    // check AGSES code
814
    if (isset($SETTINGS['agses_authentication_enabled']) && $SETTINGS['agses_authentication_enabled'] == 1 && $username != "admin") {
815
        // load AGSES
816
        include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/agses/axs/AXSILPortal_V1_Auth.php';
817
        $agses = new AXSILPortal_V1_Auth();
818
        $agses->setUrl($SETTINGS['agses_hosted_url']);
819
        $agses->setAAId($SETTINGS['agses_hosted_id']);
820
        //for release there will be another api-key - this is temporary only
821
        $agses->setApiKey($SETTINGS['agses_hosted_apikey']);
822
        $agses->create();
823
        //create random salt and store it into session
824
        if (!isset($_SESSION['hedgeId']) || $_SESSION['hedgeId'] == "") {
825
            $_SESSION['hedgeId'] = md5(time());
826
        }
827
828
        $responseCode = $passwordClear;
829
        if ($responseCode != "" && strlen($responseCode) >= 4) {
830
            // Verify response code, store result in session
831
            $result = $agses->verifyResponse(
832
                (string) $_SESSION['user_settings']['agses-usercardid'],
833
                $responseCode,
834
                (string) $_SESSION['hedgeId']
835
            );
836
837
            if ($result == 1) {
838
                $return = "";
839
                $logError = "";
840
                $proceedIdentification = true;
841
                $userPasswordVerified = true;
842
                unset($_SESSION['hedgeId']);
843
                unset($_SESSION['flickercode']);
844
            } else {
845
                if ($result < -10) {
846
                    $logError = "ERROR: ".$result;
847
                } elseif ($result == -4) {
848
                    $logError = "Wrong response code, no more tries left.";
849
                } elseif ($result == -3) {
850
                    $logError = "Wrong response code, try to reenter.";
851
                } elseif ($result == -2) {
852
                    $logError = "Timeout. The response code is not valid anymore.";
853
                } elseif ($result == -1) {
854
                    $logError = "Security Error. Did you try to verify the response from a different computer?";
855
                } elseif ($result == 1) {
856
                    $logError = "Authentication successful, response code correct.
857
                          <br /><br />Authentification Method for SecureBrowser updated!";
858
                    // Add necessary code here for accessing your Business Application
859
                }
860
                $return = "agses_error";
861
                echo '[{"value" : "'.$return.'", "user_admin":"',
862
                isset($_SESSION['user_admin']) ? $_SESSION['user_admin'] : "",
863
                '", "initial_url" : "'.@$_SESSION['initial_url'].'",
864
                "error" : "'.$logError.'"}]';
865
866
                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...
867
            }
868
        } else {
869
            // We have an error here
870
            $return = "agses_error";
871
            $logError = "No response code given";
872
873
            echo '[{"value" : "'.$return.'", "user_admin":"',
874
            isset($_SESSION['user_admin']) ? $_SESSION['user_admin'] : "",
875
            '", "initial_url" : "'.@$_SESSION['initial_url'].'",
876
            "error" : "'.$logError.'"}]';
877
878
            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...
879
        }
880
    }
881
882
    // If admin user then check if folder install exists
883
    // if yes then refuse connection
884
    if ($data['admin'] === "1" && is_dir("../install")) {
885
        $return = "install_error";
886
        $logError = "Install folder has to be removed!";
887
888
        echo '[{"value" : "'.$return.'", "user_admin":"',
889
        isset($_SESSION['user_admin']) ? $antiXss->xss_clean($_SESSION['user_admin']) : "",
890
        '", "initial_url" : "'.@$_SESSION['initial_url'].'",
891
        "error" : "'.$logError.'"}]';
892
893
        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...
894
    }
895
896
    if ($proceedIdentification === true) {
897
        // User exists in the DB
898
        if (crypt($passwordClear, $data['pw']) == $data['pw'] && !empty($data['pw'])) {
899
            //update user's password
900
            $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
901
            DB::update(
902
                prefix_table('users'),
903
                array(
904
                    'pw' => $data['pw']
905
                ),
906
                "id=%i",
907
                $data['id']
908
            );
909
        }
910
911
        // check the given password
912
        if ($userPasswordVerified !== true) {
0 ignored issues
show
introduced by
The condition $userPasswordVerified !== true is always true.
Loading history...
913
            if ($pwdlib->verifyPasswordHash($passwordClear, $data['pw']) === true) {
914
                $userPasswordVerified = true;
915
            } else {
916
                $userPasswordVerified = false;
917
                logEvents('failed_auth', 'user_password_not_correct', "", stripslashes($username));
918
            }
919
        }
920
921
        if ($debugDuo == 1) {
922
            fputs(
923
                $dbgDuo,
924
                "User's password verified: ".$userPasswordVerified."\n"
925
            );
926
        }
927
928
        // Can connect if
929
        // 1- no LDAP mode + user enabled + pw ok
930
        // 2- LDAP mode + user enabled + ldap connection ok + user is not admin
931
        // 3-  LDAP mode + user enabled + pw ok + usre is admin
932
        // This in order to allow admin by default to connect even if LDAP is activated
933
        if ((
934
                isset($SETTINGS['ldap_mode']) && $SETTINGS['ldap_mode'] === '0'
935
                && $userPasswordVerified === true && $data['disabled'] == 0
936
            )
937
            ||
938
            (
939
                isset($SETTINGS['ldap_mode']) && $SETTINGS['ldap_mode'] === '1'
940
                && $ldapConnection === true && $data['disabled'] === '0' && $username != "admin"
941
            )
942
            ||
943
            (
944
                isset($SETTINGS['ldap_mode']) && $SETTINGS['ldap_mode'] === '2'
945
                && $ldapConnection === true && $data['disabled'] === '0' && $username != "admin"
946
            )
947
            ||
948
            (
949
                isset($SETTINGS['ldap_mode']) && $SETTINGS['ldap_mode'] === '1'
950
                && $username == "admin" && $userPasswordVerified === true && $data['disabled'] === '0'
951
            )
952
            ||
953
            (
954
                isset($SETTINGS['ldap_and_local_authentication']) && $SETTINGS['ldap_and_local_authentication'] === '1'
955
                && isset($SETTINGS['ldap_mode']) && in_array($SETTINGS['ldap_mode'], array('1', '2')) === true
956
                && $userPasswordVerified === true && $data['disabled'] == 0
957
            )
958
        ) {
959
            $_SESSION['autoriser'] = true;
960
            $_SESSION["pwd_attempts"] = 0;
961
962
            // Generate a ramdom ID
963
            $key = GenerateCryptKey(50);
964
965
            if ($debugDuo == 1) {
966
                fputs(
967
                    $dbgDuo,
968
                    "User's token: ".$key."\n"
969
                );
970
            }
971
972
            // Log into DB the user's connection
973
            if (isset($SETTINGS['log_connections']) && $SETTINGS['log_connections'] === '1') {
974
                logEvents('user_connection', 'connection', $data['id'], stripslashes($username));
975
            }
976
            // Save account in SESSION
977
            $_SESSION['login'] = stripslashes($username);
978
            $_SESSION['name'] = stripslashes($data['name']);
979
            $_SESSION['lastname'] = stripslashes($data['lastname']);
980
            $_SESSION['user_id'] = $data['id'];
981
            $_SESSION['user_admin'] = $data['admin'];
982
            $_SESSION['user_manager'] = $data['gestionnaire'];
983
            $_SESSION['user_can_manage_all_users'] = $data['can_manage_all_users'];
984
            $_SESSION['user_read_only'] = $data['read_only'];
985
            $_SESSION['last_pw_change'] = $data['last_pw_change'];
986
            $_SESSION['last_pw'] = $data['last_pw'];
987
            $_SESSION['can_create_root_folder'] = $data['can_create_root_folder'];
988
            $_SESSION['key'] = $key;
989
            $_SESSION['personal_folder'] = $data['personal_folder'];
990
            $_SESSION['user_language'] = $data['user_language'];
991
            $_SESSION['user_email'] = $data['email'];
992
            $_SESSION['user_ga'] = $data['ga'];
993
            $_SESSION['user_avatar'] = $data['avatar'];
994
            $_SESSION['user_avatar_thumb'] = $data['avatar_thumb'];
995
            $_SESSION['user_upgrade_needed'] = $data['upgrade_needed'];
996
            $_SESSION['user_force_relog'] = $data['force-relog'];
997
            // get personal settings
998
            if (!isset($data['treeloadstrategy']) || empty($data['treeloadstrategy'])) {
999
                $data['treeloadstrategy'] = "full";
1000
            }
1001
            $_SESSION['user_settings']['treeloadstrategy'] = $data['treeloadstrategy'];
1002
            $_SESSION['user_settings']['agses-usercardid'] = $data['agses-usercardid'];
1003
            $_SESSION['user_settings']['user_language'] = $data['user_language'];
1004
            $_SESSION['user_settings']['encrypted_psk'] = $data['encrypted_psk'];
1005
            $_SESSION['user_settings']['usertimezone'] = $data['usertimezone'];
1006
            $_SESSION['user_settings']['session_duration'] = $dataReceived['duree_session'] * 60;
1007
            $_SESSION['user_settings']['api-key'] = $data['user_api_key'];
1008
1009
1010
            // manage session expiration
1011
            $_SESSION['fin_session'] = (integer) (time() + $_SESSION['user_settings']['session_duration']);
1012
1013
            /* If this option is set user password MD5 is used as personal SALTKey */
1014
            if (isset($SETTINGS['use_md5_password_as_salt']) &&
1015
                $SETTINGS['use_md5_password_as_salt'] == 1
1016
            ) {
1017
                $_SESSION['user_settings']['clear_psk'] = md5($passwordClear);
1018
                setcookie(
1019
                    "TeamPass_PFSK_".md5($_SESSION['user_id']),
1020
                    encrypt($_SESSION['user_settings']['clear_psk'], ""),
0 ignored issues
show
Bug introduced by
It seems like encrypt($_SESSION['user_...ngs']['clear_psk'], '') can also be of type false; however, parameter $value of setcookie() does only seem to accept string, 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

1020
                    /** @scrutinizer ignore-type */ encrypt($_SESSION['user_settings']['clear_psk'], ""),
Loading history...
1021
                    time() + 60 * 60 * 24 * $SETTINGS['personal_saltkey_cookie_duration'],
1022
                    '/'
1023
                );
1024
            }
1025
1026
            if (empty($data['last_connexion'])) {
1027
                $_SESSION['derniere_connexion'] = time();
1028
            } else {
1029
                $_SESSION['derniere_connexion'] = $data['last_connexion'];
1030
            }
1031
1032
            if (!empty($data['latest_items'])) {
1033
                $_SESSION['latest_items'] = explode(';', $data['latest_items']);
1034
            } else {
1035
                $_SESSION['latest_items'] = array();
1036
            }
1037
            if (!empty($data['favourites'])) {
1038
                $_SESSION['favourites'] = explode(';', $data['favourites']);
1039
            } else {
1040
                $_SESSION['favourites'] = array();
1041
            }
1042
1043
            if (!empty($data['groupes_visibles'])) {
1044
                $_SESSION['groupes_visibles'] = @implode(';', $data['groupes_visibles']);
1045
            } else {
1046
                $_SESSION['groupes_visibles'] = array();
1047
            }
1048
            if (!empty($data['groupes_interdits'])) {
1049
                $_SESSION['groupes_interdits'] = @implode(';', $data['groupes_interdits']);
1050
            } else {
1051
                $_SESSION['groupes_interdits'] = array();
1052
            }
1053
            // User's roles
1054
            $_SESSION['fonction_id'] = $data['fonction_id'];
1055
            $_SESSION['user_roles'] = explode(";", $data['fonction_id']);
1056
            // build array of roles
1057
            $_SESSION['user_pw_complexity'] = 0;
1058
            $_SESSION['arr_roles'] = array();
1059
            foreach (array_filter(explode(';', $_SESSION['fonction_id'])) as $role) {
1060
                $resRoles = DB::queryFirstRow("SELECT title, complexity FROM ".prefix_table("roles_title")." WHERE id=%i", $role);
1061
                $_SESSION['arr_roles'][$role] = array(
1062
                        'id' => $role,
1063
                        'title' => $resRoles['title']
1064
                );
1065
                // get highest complexity
1066
                if ($_SESSION['user_pw_complexity'] < $resRoles['complexity']) {
1067
                    $_SESSION['user_pw_complexity'] = $resRoles['complexity'];
1068
                }
1069
            }
1070
            // build complete array of roles
1071
            $_SESSION['arr_roles_full'] = array();
1072
            $rows = DB::query("SELECT id, title FROM ".prefix_table("roles_title")." ORDER BY title ASC");
1073
            foreach ($rows as $record) {
1074
                $_SESSION['arr_roles_full'][$record['id']] = array(
1075
                        'id' => $record['id'],
1076
                        'title' => $record['title']
1077
                );
1078
            }
1079
            // Set some settings
1080
            $_SESSION['user']['find_cookie'] = false;
1081
            $SETTINGS['update_needed'] = "";
1082
            // Update table
1083
            DB::update(
1084
                prefix_table('users'),
1085
                array(
1086
                    'key_tempo' => $_SESSION['key'],
1087
                    'last_connexion' => time(),
1088
                    'timestamp' => time(),
1089
                    'disabled' => 0,
1090
                    'no_bad_attempts' => 0,
1091
                    'session_end' => $_SESSION['fin_session'],
1092
                    'psk' => isset($psk) ? $pwdlib->createPasswordHash(htmlspecialchars_decode($psk)) : '',
1093
                    'user_ip' =>  $dataReceived['client']
1094
                ),
1095
                "id=%i",
1096
                $data['id']
1097
            );
1098
1099
            if ($debugDuo == 1) {
1100
                fputs(
1101
                    $dbgDuo,
1102
                    "Preparing to identify the user rights\n"
1103
                );
1104
            }
1105
1106
            // Get user's rights
1107
            if ($user_initial_creation_through_ldap === false) {
1108
                identifyUserRights(
1109
                    $data['groupes_visibles'],
1110
                    $_SESSION['groupes_interdits'],
1111
                    $data['admin'],
1112
                    $data['fonction_id']
1113
                );
1114
            } else {
1115
                // is new LDAP user. Show only his personal folder
1116
                if ($SETTINGS['enable_pf_feature'] === '1') {
1117
                    $_SESSION['personal_visible_groups'] = array($data['id']);
1118
                    $_SESSION['personal_folders'] = array($data['id']);
1119
                } else {
1120
                    $_SESSION['personal_visible_groups'] = array();
1121
                    $_SESSION['personal_folders'] = array();
1122
                }
1123
                $_SESSION['all_non_personal_folders'] = array();
1124
                $_SESSION['groupes_visibles'] = array();
1125
                $_SESSION['groupes_visibles_list'] = "";
1126
                $_SESSION['read_only_folders'] = array();
1127
                $_SESSION['list_folders_limited'] = "";
1128
                $_SESSION['list_folders_editable_by_role'] = array();
1129
                $_SESSION['list_restricted_folders_for_items'] = array();
1130
                $_SESSION['nb_folders'] = 1;
1131
                $_SESSION['nb_roles'] = 0;
1132
            }
1133
            // Get some more elements
1134
            $_SESSION['screenHeight'] = $dataReceived['screenHeight'];
1135
            // Get last seen items
1136
            $_SESSION['latest_items_tab'][] = "";
1137
            foreach ($_SESSION['latest_items'] as $item) {
1138
                if (!empty($item)) {
1139
                    $data = DB::queryFirstRow("SELECT id,label,id_tree FROM ".prefix_table("items")." WHERE id=%i", $item);
1140
                    $_SESSION['latest_items_tab'][$item] = array(
1141
                        'id' => $item,
1142
                        'label' => $data['label'],
1143
                        'url' => 'index.php?page=items&amp;group='.$data['id_tree'].'&amp;id='.$item
1144
                    );
1145
                }
1146
            }
1147
            // send back the random key
1148
            $return = $dataReceived['randomstring'];
1149
            // Send email
1150
            if (isset($SETTINGS['enable_send_email_on_user_login'])
1151
                    && $SETTINGS['enable_send_email_on_user_login'] === '1'
1152
                    && $_SESSION['user_admin'] != 1
1153
            ) {
1154
                // get all Admin users
1155
                $receivers = "";
1156
                $rows = DB::query("SELECT email FROM ".prefix_table("users")." WHERE admin = %i and email != ''", 1);
1157
                foreach ($rows as $record) {
1158
                    if (empty($receivers)) {
1159
                        $receivers = $record['email'];
1160
                    } else {
1161
                        $receivers = ",".$record['email'];
1162
                    }
1163
                }
1164
                // Add email to table
1165
                DB::insert(
1166
                    prefix_table("emails"),
1167
                    array(
1168
                        'timestamp' => time(),
1169
                        'subject' => $LANG['email_subject_on_user_login'],
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $LANG seems to be never defined.
Loading history...
1170
                        'body' => str_replace(
1171
                            array(
1172
                                '#tp_user#',
1173
                                '#tp_date#',
1174
                                '#tp_time#'
1175
                            ),
1176
                            array(
1177
                                " ".$_SESSION['login']." (IP: ".get_client_ip_server().")",
0 ignored issues
show
Bug introduced by
Are you sure get_client_ip_server() of type false|string|array can be used in concatenation? ( Ignorable by Annotation )

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

1177
                                " ".$_SESSION['login']." (IP: "./** @scrutinizer ignore-type */ get_client_ip_server().")",
Loading history...
1178
                                date($SETTINGS['date_format'], $_SESSION['derniere_connexion']),
1179
                                date($SETTINGS['time_format'], $_SESSION['derniere_connexion'])
1180
                            ),
1181
                            $LANG['email_body_on_user_login']
1182
                        ),
1183
                        'receivers' => $receivers,
1184
                        'status' => "not_sent"
1185
                    )
1186
                );
1187
            }
1188
        } elseif ($data['disabled'] == 1) {
1189
            // User and password is okay but account is locked
1190
            $return = "user_is_locked";
1191
        } else {
1192
            // User exists in the DB but Password is false
1193
            // check if user is locked
1194
            $userIsLocked = 0;
1195
            $nbAttempts = intval($data['no_bad_attempts'] + 1);
1196
            if ($SETTINGS['nb_bad_authentication'] > 0
1197
                    && intval($SETTINGS['nb_bad_authentication']) < $nbAttempts
1198
            ) {
1199
                $userIsLocked = 1;
1200
                // log it
1201
                if (isset($SETTINGS['log_connections'])
1202
                        && $SETTINGS['log_connections'] === '1'
1203
                ) {
1204
                    logEvents('user_locked', 'connection', $data['id'], stripslashes($username));
1205
                }
1206
            }
1207
            DB::update(
1208
                prefix_table('users'),
1209
                array(
1210
                    'key_tempo' => $_SESSION['key'],
1211
                    'last_connexion' => time(),
1212
                    'disabled' => $userIsLocked,
1213
                    'no_bad_attempts' => $nbAttempts
1214
                ),
1215
                "id=%i",
1216
                $data['id']
1217
            );
1218
            // What return shoulb we do
1219
            if ($userIsLocked == 1) {
1220
                $return = "user_is_locked";
1221
            } elseif ($SETTINGS['nb_bad_authentication'] === '0') {
1222
                $return = "false";
1223
            } else {
1224
                $return = $nbAttempts;
1225
            }
1226
        }
1227
    } else {
1228
        if ($user_initial_creation_through_ldap === true) {
1229
            $return = "new_ldap_account_created";
1230
        } else {
1231
            $return = "false";
1232
        }
1233
    }
1234
1235
    if ($debugDuo == 1) {
1236
        fputs(
1237
            $dbgDuo,
1238
            "\n\n----\n".
1239
            "Identified : ".filter_var($return, FILTER_SANITIZE_STRING)."\n\n"
1240
        );
1241
    }
1242
1243
    // manage bruteforce
1244
    if ($_SESSION["pwd_attempts"] > 2) {
1245
        $_SESSION["next_possible_pwd_attempts"] = time() + 10;
1246
    }
1247
1248
    echo '[{"value" : "'.$return.'", "user_admin":"', isset($_SESSION['user_admin']) ? $antiXss->xss_clean($_SESSION['user_admin']) : "", '", "initial_url" : "'.@$_SESSION['initial_url'].'", "error" : "'.$logError.'", "pwd_attempts" : "'.$antiXss->xss_clean($_SESSION["pwd_attempts"]).'"}]';
0 ignored issues
show
Security Cross-Site Scripting introduced by
'", "initial_url" : "' ....pwd_attempts']) . '"}]' can contain request data and is used in output context(s) leading to a potential security vulnerability.

3 paths for user data to reach this point

  1. Path: Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username in sources/identify.php on line 335
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 335
  2. Data is passed through stripslashes(), and stripslashes($username) is assigned to $_SESSION
    in sources/identify.php on line 977
  2. Path: Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username in sources/identify.php on line 333
  1. Read tainted data from array, and Data is passed through explode(), and explode('\', $_SERVER['PHP_AUTH_USER'])[1] is assigned to $username
    in sources/identify.php on line 333
  2. Data is passed through stripslashes(), and stripslashes($username) is assigned to $_SESSION
    in sources/identify.php on line 977
  3. Path: Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username in sources/identify.php on line 331
  1. Read tainted data from array, and Data is passed through explode(), and explode('@', $_SERVER['PHP_AUTH_USER'])[0] is assigned to $username
    in sources/identify.php on line 331
  2. Data is passed through stripslashes(), and stripslashes($username) is assigned to $_SESSION
    in sources/identify.php on line 977

Preventing Cross-Site-Scripting Attacks

Cross-Site-Scripting allows an attacker to inject malicious code into your website - in particular Javascript code, and have that code executed with the privileges of a visiting user. This can be used to obtain data, or perform actions on behalf of that visiting user.

In order to prevent this, make sure to escape all user-provided data:

// for HTML
$sanitized = htmlentities($tainted, ENT_QUOTES);

// for URLs
$sanitized = urlencode($tainted);

General Strategies to prevent injection

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

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

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

$sanitized = (integer) $tainted;
Loading history...
Bug introduced by
Are you sure $antiXss->xss_clean($_SESSION['pwd_attempts']) of type string|array can be used in concatenation? ( Ignorable by Annotation )

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

1248
    echo '[{"value" : "'.$return.'", "user_admin":"', isset($_SESSION['user_admin']) ? $antiXss->xss_clean($_SESSION['user_admin']) : "", '", "initial_url" : "'.@$_SESSION['initial_url'].'", "error" : "'.$logError.'", "pwd_attempts" : "'./** @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION["pwd_attempts"]).'"}]';
Loading history...
1249
1250
    $_SESSION['initial_url'] = "";
1251
    if ($SETTINGS['cpassman_dir'] === '..') {
1252
        $SETTINGS['cpassman_dir'] = '.';
1253
    }
1254
}
1255