Passed
Push — development ( ee13b6...7c2d55 )
by Nils
04:34
created

identifyUser()   F

Complexity

Conditions 186
Paths > 20000

Size

Total Lines 1000
Code Lines 646

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 186
eloc 646
c 2
b 0
f 0
nc 1788500481
nop 4
dl 0
loc 1000
rs 2

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 275 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(
234
            $post_data,
235
            $debugLdap,
236
            $debugDuo,
237
            $SETTINGS
238
        );
239
    } elseif (isset($_SESSION["next_possible_pwd_attempts"]) && time() > $_SESSION["next_possible_pwd_attempts"] && $_SESSION["pwd_attempts"] > 3) {
240
        $_SESSION["pwd_attempts"] = 1;
241
        // identify the user through Teampass process
242
        identifyUser(
243
            $post_data,
244
            $debugLdap,
245
            $debugDuo,
246
            $SETTINGS
247
        );
248
    } else {
249
        $_SESSION["next_possible_pwd_attempts"] = time() + 10;
250
        echo '[{"error" : "bruteforce_wait"}]';
251
        return false;
252
    }
253
} elseif ($post_type === "store_data_in_cookie") {
254
    //--------
255
    // STORE DATA IN COOKIE
256
    //--------
257
    //
258
    // not used any more (only development purpose)
259
    if ($post_key !== $_SESSION['key']) {
260
        echo '[{"error" : "something_wrong"}]';
261
        return false;
262
    }
263
    // store some connection data in cookie
264
    setcookie(
265
        "TeamPassC",
266
        $post_data,
267
        time() + 60 * 60,
268
        '/'
269
    );
270
}
271
272
/*
273
* Complete authentication of user through Teampass
274
*/
275
function identifyUser(
276
    $sentData,
277
    $debugLdap,
278
    $debugDuo,
279
    $SETTINGS
280
) {
281
    // Load config
282
    if (file_exists('../includes/config/tp.config.php')) {
283
        include_once '../includes/config/tp.config.php';
284
    } elseif (file_exists('./includes/config/tp.config.php')) {
285
        include_once './includes/config/tp.config.php';
286
    } else {
287
        throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
288
    }
289
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
290
291
    header("Content-type: text/html; charset=utf-8");
292
    error_reporting(E_ERROR);
293
    include_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
294
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
295
296
    // Load AntiXSS
297
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
298
    $antiXss = new protect\AntiXSS\AntiXSS();
299
300
    // Load superGlobals
301
    require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
302
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
303
304
    // Prepare GET variables
305
    $session_user_language = $superGlobal->get("user_language", "SESSION");
306
307
    if ($debugDuo == 1) {
308
        $dbgDuo = fopen($SETTINGS['path_to_files_folder']."/duo.debug.txt", "a");
309
310
        fputs(
311
            $dbgDuo,
0 ignored issues
show
Bug introduced by
It seems like $dbgDuo 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

311
            /** @scrutinizer ignore-type */ $dbgDuo,
Loading history...
312
            "Content of data sent '".filter_var($sentData, FILTER_SANITIZE_STRING)."'\n"
313
        );
314
    }
315
316
    // connect to the server
317
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
318
    $pass = defuse_return_decrypted($pass);
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $pass seems to be never defined.
Loading history...
319
    DB::$host = $server;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $server seems to be never defined.
Loading history...
320
    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...
321
    DB::$password = $pass;
322
    DB::$dbName = $database;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $database seems to be never defined.
Loading history...
323
    DB::$port = $port;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $port seems to be never defined.
Loading history...
324
    DB::$encoding = $encoding;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $encoding seems to be never defined.
Loading history...
325
    DB::$error_handler = true;
326
    $link = mysqli_connect($server, $user, $pass, $database, $port);
327
    $link->set_charset($encoding);
328
329
    // load passwordLib library
330
    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'].'/includes/libraries');
331
    $pwdlib->register();
332
    $pwdlib = new PasswordLib\PasswordLib();
333
334
    // User's language loading
335
    include_once $SETTINGS['cpassman_dir'].'/includes/language/'.$session_user_language.'.php';
336
337
    // decrypt and retreive data in JSON format
338
    $dataReceived = prepareExchangedData($sentData, "decode");
339
340
    // prepare variables
341
    if (isset($SETTINGS['enable_http_request_login']) === true
342
        && $SETTINGS['enable_http_request_login'] === '1'
343
        && isset($_SERVER['PHP_AUTH_USER']) === true
344
        && isset($SETTINGS['maintenance_mode']) === true
345
        && $SETTINGS['maintenance_mode'] === '1'
346
    ) {
347
        if (strpos($_SERVER['PHP_AUTH_USER'], '@') !== false) {
348
            $username = explode("@", $_SERVER['PHP_AUTH_USER'])[0];
349
        } elseif (strpos($_SERVER['PHP_AUTH_USER'], '\\') !== false) {
350
            $username = explode("\\", $_SERVER['PHP_AUTH_USER'])[1];
351
        } else {
352
            $username = $_SERVER['PHP_AUTH_USER'];
353
        }
354
        $passwordClear = $_SERVER['PHP_AUTH_PW'];
355
    } else {
356
        $passwordClear = htmlspecialchars_decode($dataReceived['pw']);
357
        $username = $antiXss->xss_clean(htmlspecialchars_decode($dataReceived['login']));
358
    }
359
    $logError = "";
360
    $userPasswordVerified = false;
361
362
    if ($debugDuo == 1) {
363
        fputs(
364
            $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...
365
            "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 352
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 352
  2. 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 348
  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 348
  3. 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 350
  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 350

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...
366
        );
367
    }
368
369
    $ldapConnection = false;
370
371
    /* LDAP connection */
372
    if ($debugLdap == 1) {
373
        // create temp file
374
        $dbgLdap = fopen($SETTINGS['path_to_files_folder']."/ldap.debug.txt", "w");
375
        fputs(
376
            $dbgLdap,
377
            "Get all LDAP params : \n".
378
            'mode : '.$SETTINGS['ldap_mode']."\n".
379
            'type : '.$SETTINGS['ldap_type']."\n".
380
            'base_dn : '.$SETTINGS['ldap_domain_dn']."\n".
381
            'search_base : '.$SETTINGS['ldap_search_base']."\n".
382
            'bind_dn : '.$SETTINGS['ldap_bind_dn']."\n".
383
            'bind_passwd : '.$SETTINGS['ldap_bind_passwd']."\n".
384
            'user_attribute : '.$SETTINGS['ldap_user_attribute']."\n".
385
            'account_suffix : '.$SETTINGS['ldap_suffix']."\n".
386
            'domain_controllers : '.$SETTINGS['ldap_domain_controler']."\n".
387
            'ad_port : '.$SETTINGS['ldap_port']."\n".
388
            'use_ssl : '.$SETTINGS['ldap_ssl']."\n".
389
            'use_tls : '.$SETTINGS['ldap_tls']."\n*********\n\n"
390
        );
391
    }
392
393
    if ($debugDuo == 1) {
394
        fputs(
395
            $dbgDuo,
396
            "LDAP status: ".$SETTINGS['ldap_mode']."\n"
397
        );
398
    }
399
400
    // Check if user exists
401
    $data = DB::queryFirstRow(
402
        "SELECT * FROM ".prefix_table("users")." WHERE login=%s_login",
403
        array(
404
            'login' => $username
405
        )
406
    );
407
    $counter = DB::count();
408
    $user_initial_creation_through_ldap = false;
409
    $proceedIdentification = false;
410
411
    // Prepare LDAP connection if set up
412
    if (isset($SETTINGS['ldap_mode'])
413
        && $SETTINGS['ldap_mode'] === '1'
414
        && $username !== "admin"
415
    ) {
416
        //Multiple Domain Names
417
        if (strpos(html_entity_decode($username), '\\') === true) {
418
            $ldap_suffix = "@".substr(html_entity_decode($username), 0, strpos(html_entity_decode($username), '\\'));
419
            $username = substr(html_entity_decode($username), strpos(html_entity_decode($username), '\\') + 1);
420
        }
421
        if ($SETTINGS['ldap_type'] === 'posix-search') {
422
            $ldapURIs = "";
423
            foreach (explode(",", $SETTINGS['ldap_domain_controler']) as $domainControler) {
424
                if ($SETTINGS['ldap_ssl'] == 1) {
425
                    $ldapURIs .= "ldaps://".$domainControler.":".$SETTINGS['ldap_port']." ";
426
                } else {
427
                    $ldapURIs .= "ldap://".$domainControler.":".$SETTINGS['ldap_port']." ";
428
                }
429
            }
430
            if ($debugLdap == 1) {
431
                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...
432
            }
433
            $ldapconn = ldap_connect($ldapURIs);
434
435
            if ($SETTINGS['ldap_tls']) {
436
                ldap_start_tls($ldapconn);
437
            }
438
            if ($debugLdap == 1) {
439
                fputs($dbgLdap, "LDAP connection : ".($ldapconn ? "Connected" : "Failed")."\n");
0 ignored issues
show
introduced by
The condition $ldapconn is always false.
Loading history...
440
            }
441
            ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
442
            ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
443
444
            // Is LDAP connection ready?
445
            if ($ldapconn !== false) {
446
                // Should we bind the connection?
447
                if ($SETTINGS['ldap_bind_dn'] !== "" && $SETTINGS['ldap_bind_passwd'] !== "") {
448
                    $ldapbind = ldap_bind($ldapconn, $SETTINGS['ldap_bind_dn'], $SETTINGS['ldap_bind_passwd']);
449
                    if ($debugLdap == 1) {
450
                        fputs($dbgLdap, "LDAP bind : ".($ldapbind ? "Bound" : "Failed")."\n");
451
                    }
452
                }
453
                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...
454
                    $filter = "(&(".$SETTINGS['ldap_user_attribute']."=".$username.")(objectClass=".$SETTINGS['ldap_object_class']."))";
455
                    $result = ldap_search(
456
                      $ldapconn,
457
                      $SETTINGS['ldap_search_base'],
458
                      $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 352
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 352
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 454
  2. 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 348
  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 348
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 454
  3. 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 350
  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 350
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 454

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...
459
                      array('dn', 'mail', 'givenname', 'sn')
460
                    );
461
                    if ($debugLdap == 1) {
462
                        fputs(
463
                            $dbgLdap,
464
                            '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 352
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 352
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 454
  2. 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 348
  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 348
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 454
  3. 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 350
  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 350
  2. '(&(' . $SETTINGS['ldap_user_attribute'] . '=' . $username . ')(objectClass=' . $SETTINGS['ldap_object_class'] . '))' is assigned to $filter
    in sources/identify.php on line 454

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...
465
                            'Results : '.print_r(ldap_get_entries($ldapconn, $result), true)."\n"
466
                        );
467
                    }
468
469
                    // Check if user was found in AD
470
                    if (ldap_count_entries($ldapconn, $result) > 0) {
471
                        // Get user's info and especially the DN
472
                        $result = ldap_get_entries($ldapconn, $result);
473
                        $user_dn = $result[0]['dn'];
474
475
                        fputs(
476
                            $dbgLdap,
477
                            'User was found. '.$user_dn.'\n'
478
                        );
479
480
                        // Should we restrain the search in specified user groups
481
                        $GroupRestrictionEnabled = false;
482
                        if (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === false) {
483
                            // New way to check User's group membership
484
                            $filter_group = "memberUid=".$username;
485
                            $result_group = ldap_search(
486
                                $ldapconn,
487
                                $SETTINGS['ldap_search_base'],
488
                                $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 352
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 352
  2. 'memberUid=' . $username is assigned to $filter_group
    in sources/identify.php on line 484
  2. 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 348
  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 348
  2. 'memberUid=' . $username is assigned to $filter_group
    in sources/identify.php on line 484
  3. 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 350
  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 350
  2. 'memberUid=' . $username is assigned to $filter_group
    in sources/identify.php on line 484

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...
489
                                array('dn')
490
                            );
491
492
                            if ($result_group) {
0 ignored issues
show
introduced by
The condition $result_group is always false.
Loading history...
493
                                $entries = ldap_get_entries($ldapconn, $result_group);
494
495
                                if ($debugLdap == 1) {
496
                                    fputs(
497
                                        $dbgLdap,
498
                                        'Search groups appartenance : '.$SETTINGS['ldap_search_base']."\n".
499
                                        'Results : '.print_r($entries, true)."\n"
500
                                    );
501
                                }
502
503
                                if ($entries['count'] > 0) {
504
                                    // Now check if group fits
505
                                    for ($i=0; $i<$entries['count']; $i++) {
506
                                      $parsr=ldap_explode_dn($entries[$i]['dn'], 0);
507
                                      if (str_replace(array('CN=','cn='), '', $parsr[0]) === $SETTINGS['ldap_usergroup']) {
508
                                        $GroupRestrictionEnabled = true;
509
                                        break;
510
                                      }
511
                                    }
512
513
                                }
514
                            }
515
516
                            if ($debugLdap == 1) {
517
                                fputs(
518
                                    $dbgLdap,
519
                                    '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

519
                                    'Group was found : './** @scrutinizer ignore-type */ $GroupRestrictionEnabled."\n"
Loading history...
520
                                );
521
                            }
522
                        }
523
524
                        // Is user in the LDAP?
525
                        if ($GroupRestrictionEnabled === true
526
                            || (
527
                                $GroupRestrictionEnabled === false
528
                                && (isset($SETTINGS['ldap_usergroup']) === false
529
                                    || (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === true)
530
                                )
531
                            )
532
                        ) {
533
                            // Try to auth inside LDAP
534
                            $ldapbind = ldap_bind($ldapconn, $user_dn, $passwordClear);
535
                            if ($ldapbind === true) {
536
                                $ldapConnection = true;
537
538
                                // Update user's password
539
                                $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
540
541
                                // Do things if user exists in TP
542
                                if ($counter > 0) {
543
                                    // Update pwd in TP database
544
                                    DB::update(
545
                                        prefix_table('users'),
546
                                        array(
547
                                            'pw' => $data['pw']
548
                                        ),
549
                                        "login=%s",
550
                                        $username
551
                                    );
552
553
                                    // No user creation is requested
554
                                    $proceedIdentification = true;
555
                                }
556
                            } else {
557
                                $ldapConnection = false;
558
                            }
559
                        }
560
                    } else {
561
                        $ldapConnection = false;
562
                    }
563
                } else {
564
                    $ldapConnection = false;
565
                }
566
            } else {
567
                $ldapConnection = false;
568
            }
569
        } else {
570
            if ($debugLdap == 1) {
571
                fputs(
572
                    $dbgLdap,
573
                    "Get all ldap params : \n".
574
                    'base_dn : '.$SETTINGS['ldap_domain_dn']."\n".
575
                    'account_suffix : '.$SETTINGS['ldap_suffix']."\n".
576
                    'domain_controllers : '.$SETTINGS['ldap_domain_controler']."\n".
577
                    'ad_port : '.$SETTINGS['ldap_port']."\n".
578
                    'use_ssl : '.$SETTINGS['ldap_ssl']."\n".
579
                    'use_tls : '.$SETTINGS['ldap_tls']."\n*********\n\n"
580
                );
581
            }
582
            $adldap = new SplClassLoader('adLDAP', '../includes/libraries/LDAP');
583
            $adldap->register();
584
585
            // Posix style LDAP handles user searches a bit differently
586
            if ($SETTINGS['ldap_type'] === 'posix') {
587
                $ldap_suffix = ','.$SETTINGS['ldap_suffix'].','.$SETTINGS['ldap_domain_dn'];
588
            } elseif ($SETTINGS['ldap_type'] === 'windows' && empty($ldap_suffix) === true) {
589
                //Multiple Domain Names
590
                $ldap_suffix = $SETTINGS['ldap_suffix'];
591
            }
592
593
            // Ensure no double commas exist in ldap_suffix
594
            $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...
595
596
            // Create LDAP connection
597
            $adldap = new adLDAP\adLDAP(
598
                array(
599
                    'base_dn' => $SETTINGS['ldap_domain_dn'],
600
                    'account_suffix' => $ldap_suffix,
601
                    'domain_controllers' => explode(",", $SETTINGS['ldap_domain_controler']),
602
                    'ad_port' => $SETTINGS['ldap_port'],
603
                    'use_ssl' => $SETTINGS['ldap_ssl'],
604
                    'use_tls' => $SETTINGS['ldap_tls']
605
                )
606
            );
607
608
            if ($debugLdap == 1) {
609
                fputs($dbgLdap, "Create new adldap object : ".$adldap->getLastError()."\n\n\n"); //Debug
610
            }
611
612
            // OpenLDAP expects an attribute=value pair
613
            if ($SETTINGS['ldap_type'] === 'posix') {
614
                $auth_username = $SETTINGS['ldap_user_attribute'].'='.$username;
615
            } else {
616
                $auth_username = $username;
617
            }
618
619
            // Authenticate the user
620
            if ($adldap->authenticate($auth_username, html_entity_decode($passwordClear))) {
621
                // Is user in allowed group
622
                if (isset($SETTINGS['ldap_allowed_usergroup']) === true
623
                    && empty($SETTINGS['ldap_allowed_usergroup']) === false
624
                ) {
625
                    if ($adldap->user()->inGroup($auth_username, $SETTINGS['ldap_allowed_usergroup']) === true) {
626
                        $ldapConnection = true;
627
                    } else {
628
                        $ldapConnection = false;
629
                    }
630
                } else {
631
                    $ldapConnection = true;
632
                }
633
634
                // Update user's password
635
                if ($ldapConnection === true) {
636
                    $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
637
638
                    // Do things if user exists in TP
639
                    if ($counter > 0) {
640
                        // Update pwd in TP database
641
                        DB::update(
642
                            prefix_table('users'),
643
                            array(
644
                                'pw' => $data['pw']
645
                            ),
646
                            "login=%s",
647
                            $username
648
                        );
649
650
                        // No user creation is requested
651
                        $proceedIdentification = true;
652
                    }
653
                }
654
            } else {
655
                $ldapConnection = false;
656
            }
657
            if ($debugLdap == 1) {
658
                fputs(
659
                    $dbgLdap,
660
                    "After authenticate : ".$adldap->getLastError()."\n\n\n".
661
                    "ldap status : ".$ldapConnection."\n\n\n"
662
                ); //Debug
663
            }
664
        }
665
    } 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...
666
        // nothing
667
    }
668
    if ($debugDuo == 1) {
669
        fputs(
670
            $dbgDuo,
671
            "USer exists: ".$counter."\n"
672
        );
673
    }
674
675
676
    // Check PSK
677
    if (isset($SETTINGS['psk_authentication'])
678
        && $SETTINGS['psk_authentication'] === "1"
679
        && $data['admin'] !== "1"
680
    ) {
681
        $psk = htmlspecialchars_decode($dataReceived['psk']);
682
        $pskConfirm = htmlspecialchars_decode($dataReceived['psk_confirm']);
683
        if (empty($psk)) {
684
            echo '[{"value" : "psk_required"}]';
685
            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...
686
        } elseif (empty($data['psk'])) {
687
            if (empty($pskConfirm)) {
688
                echo '[{"value" : "bad_psk_confirmation"}]';
689
                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...
690
            } else {
691
                $_SESSION['user_settings']['clear_psk'] = $psk;
692
            }
693
        } elseif ($pwdlib->verifyPasswordHash($psk, $data['psk']) === true) {
694
            echo '[{"value" : "bad_psk"}]';
695
            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...
696
        }
697
    }
698
699
700
    // Create new LDAP user if not existing in Teampass
701
    // Don't create it if option "only localy declared users" is enabled
702
    if ($counter == 0 && $ldapConnection === true && isset($SETTINGS['ldap_elusers'])
703
        && ($SETTINGS['ldap_elusers'] == 0)
704
    ) {
705
        // If LDAP enabled, create user in TEAMPASS if doesn't exist
706
707
        // Get user info from LDAP
708
        if ($SETTINGS['ldap_type'] === 'posix-search') {
709
            //Because we didn't use adLDAP, we need to set the user info from the ldap_get_entries result
710
            $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...
711
        } else {
712
            $user_info_from_ad = $adldap->user()->info($auth_username, array("mail", "givenname", "sn"));
0 ignored issues
show
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...
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...
713
        }
714
715
        DB::insert(
716
            prefix_table('users'),
717
            array(
718
                'login' => $username,
719
                'pw' => $data['pw'],
720
                'email' => (isset($user_info_from_ad[0]['mail'][0]) === false) ? '' : $user_info_from_ad[0]['mail'][0],
721
                'name' => $user_info_from_ad[0]['givenname'][0],
722
                'lastname' => $user_info_from_ad[0]['sn'][0],
723
                'admin' => '0',
724
                'gestionnaire' => '0',
725
                'can_manage_all_users' => '0',
726
                'personal_folder' => $SETTINGS['enable_pf_feature'] === "1" ? '1' : '0',
727
                'fonction_id' => isset($SETTINGS['ldap_new_user_role']) === true ? $SETTINGS['ldap_new_user_role'] : '0',
728
                'groupes_interdits' => '',
729
                'groupes_visibles' => '',
730
                'last_pw_change' => time(),
731
                'user_language' => $SETTINGS['default_language'],
732
                'encrypted_psk' => '',
733
                '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
734
            )
735
        );
736
        $newUserId = DB::insertId();
737
        // Create personnal folder
738
        if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === "1") {
739
            DB::insert(
740
                prefix_table("nested_tree"),
741
                array(
742
                    'parent_id' => '0',
743
                    'title' => $newUserId,
744
                    'bloquer_creation' => '0',
745
                    'bloquer_modification' => '0',
746
                    'personal_folder' => '1'
747
                )
748
            );
749
        }
750
        $proceedIdentification = true;
751
        $user_initial_creation_through_ldap = true;
752
    }
753
754
    // Check if user exists (and has been created in case of new LDAP user)
755
    $data = DB::queryFirstRow(
756
        "SELECT * FROM ".prefix_table("users")." WHERE login=%s_login",
757
        array(
758
            'login' => $username
759
        )
760
    );
761
    $counter = DB::count();
762
    if ($counter === 0) {
763
        logEvents('failed_auth', 'user_not_exists', "", stripslashes($username));
764
        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 352
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 352
  2. 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 348
  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 348
  3. 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 350
  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 350

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...
765
        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...
766
    }
767
768
    // check GA code
769
    if (isset($SETTINGS['google_authentication']) && $SETTINGS['google_authentication'] == 1 && $username !== "admin") {
770
        if (isset($dataReceived['GACode']) && empty($dataReceived['GACode']) === false) {
771
            // load library
772
            include_once($SETTINGS['cpassman_dir']."/includes/libraries/Authentication/TwoFactorAuth/TwoFactorAuth.php");
773
774
            // create new instance
775
            $tfa = new Authentication\TwoFactorAuth\TwoFactorAuth($SETTINGS['ga_website_name']);
776
777
            // now check if it is the 1st time the user is using 2FA
778
            if ($data['ga_temporary_code'] !== "none" && $data['ga_temporary_code'] !== "done") {
779
                if ($data['ga_temporary_code'] !== $dataReceived['GACode']) {
780
                    $proceedIdentification = false;
781
                    $logError = "ga_temporary_code_wrong";
782
                } else {
783
                    $proceedIdentification = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $proceedIdentification is dead and can be removed.
Loading history...
784
                    $logError = "ga_temporary_code_correct";
785
786
                    // generate new QR
787
                    $new_2fa_qr = $tfa->getQRCodeImageAsDataUri("Teampass - ".$username, $data['ga']);
788
789
                    // clear temporary code from DB
790
                    DB::update(
791
                        prefix_table('users'),
792
                        array(
793
                            'ga_temporary_code' => 'done'
794
                        ),
795
                        "id=%i",
796
                        $data['id']
797
                    );
798
799
                    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

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

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

1199
                                " ".$_SESSION['login']." (IP: "./** @scrutinizer ignore-type */ get_client_ip_server().")",
Loading history...
1200
                                date($SETTINGS['date_format'], $_SESSION['derniere_connexion']),
1201
                                date($SETTINGS['time_format'], $_SESSION['derniere_connexion'])
1202
                            ),
1203
                            $LANG['email_body_on_user_login']
1204
                        ),
1205
                        'receivers' => $receivers,
1206
                        'status' => "not_sent"
1207
                    )
1208
                );
1209
            }
1210
        } elseif ($data['disabled'] == 1) {
1211
            // User and password is okay but account is locked
1212
            $return = "user_is_locked";
1213
        } else {
1214
            // User exists in the DB but Password is false
1215
            // check if user is locked
1216
            $userIsLocked = 0;
1217
            $nbAttempts = intval($data['no_bad_attempts'] + 1);
1218
            if ($SETTINGS['nb_bad_authentication'] > 0
1219
                    && intval($SETTINGS['nb_bad_authentication']) < $nbAttempts
1220
            ) {
1221
                $userIsLocked = 1;
1222
                // log it
1223
                if (isset($SETTINGS['log_connections'])
1224
                        && $SETTINGS['log_connections'] === '1'
1225
                ) {
1226
                    logEvents('user_locked', 'connection', $data['id'], stripslashes($username));
1227
                }
1228
            }
1229
            DB::update(
1230
                prefix_table('users'),
1231
                array(
1232
                    'key_tempo' => $_SESSION['key'],
1233
                    'last_connexion' => time(),
1234
                    'disabled' => $userIsLocked,
1235
                    'no_bad_attempts' => $nbAttempts
1236
                ),
1237
                "id=%i",
1238
                $data['id']
1239
            );
1240
            // What return shoulb we do
1241
            if ($userIsLocked == 1) {
1242
                $return = "user_is_locked";
1243
            } elseif ($SETTINGS['nb_bad_authentication'] === '0') {
1244
                $return = "false";
1245
            } else {
1246
                $return = $nbAttempts;
1247
            }
1248
        }
1249
    } else {
1250
        if ($user_initial_creation_through_ldap === true) {
1251
            $return = "new_ldap_account_created";
1252
        } else {
1253
            $return = "false";
1254
        }
1255
    }
1256
1257
    if ($debugDuo == 1) {
1258
        fputs(
1259
            $dbgDuo,
1260
            "\n\n----\n".
1261
            "Identified : ".filter_var($return, FILTER_SANITIZE_STRING)."\n\n"
1262
        );
1263
    }
1264
1265
    // manage bruteforce
1266
    if ($_SESSION["pwd_attempts"] > 2) {
1267
        $_SESSION["next_possible_pwd_attempts"] = time() + 10;
1268
    }
1269
1270
    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 352
  1. Read tainted data from array, and $_SERVER['PHP_AUTH_USER'] is assigned to $username
    in sources/identify.php on line 352
  2. Data is passed through stripslashes(), and stripslashes($username) is assigned to $_SESSION
    in sources/identify.php on line 992
  2. 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 348
  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 348
  2. Data is passed through stripslashes(), and stripslashes($username) is assigned to $_SESSION
    in sources/identify.php on line 992
  3. 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 350
  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 350
  2. Data is passed through stripslashes(), and stripslashes($username) is assigned to $_SESSION
    in sources/identify.php on line 992

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

1270
    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...
1271
1272
    $_SESSION['initial_url'] = "";
1273
    if ($SETTINGS['cpassman_dir'] === '..') {
1274
        $SETTINGS['cpassman_dir'] = '.';
1275
    }
1276
}
1277