Passed
Push — teampass_3.0 ( adeba0...faf37d )
by Nils
03:44
created

ldapCreateUser()   B

Complexity

Conditions 8
Paths 2

Size

Total Lines 49
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 8
eloc 38
c 1
b 0
f 0
nc 2
nop 4
dl 0
loc 49
rs 8.0675
1
<?php
2
/**
3
 * Teampass - a collaborative passwords manager.
4
 *
5
 * This library is distributed in the hope that it will be useful,
6
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
7
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8
 *
9
 * @category  Teampass
10
 *
11
 * @author    Nils Laumaillé <[email protected]>
12
 * @copyright 2009-2018 Nils Laumaillé
13
* @license   https://spdx.org/licenses/GPL-3.0-only.html#licenseText GPL-3.0
14
*
15
 * @version   GIT: <git_id>
16
 *
17
 * @see      http://www.teampass.net
18
 */
19
$debugLdap = 0; //Can be used in order to debug LDAP authentication
20
$debugDuo = 0; //Can be used in order to debug DUO authentication
21
22
require_once 'SecureHandler.php';
23
session_start();
24
if (!isset($_SESSION['CPM']) || $_SESSION['CPM'] !== 1) {
25
    die('Hacking attempt...');
26
}
27
28
// Load config
29
if (file_exists('../includes/config/tp.config.php')) {
30
    include_once '../includes/config/tp.config.php';
31
} elseif (file_exists('./includes/config/tp.config.php')) {
32
    include_once './includes/config/tp.config.php';
33
} else {
34
    throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
35
}
36
37
if (!isset($SETTINGS['cpassman_dir']) || empty($SETTINGS['cpassman_dir']) === true || $SETTINGS['cpassman_dir'] === '.') {
38
    $SETTINGS['cpassman_dir'] = '..';
39
}
40
41
// Load AntiXSS
42
require_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
43
$antiXss = new protect\AntiXSS\AntiXSS();
44
45
require_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
46
47
// init
48
$dbgDuo = '';
49
$dbgLdap = '';
50
$ldap_suffix = '';
51
$result = '';
52
$adldap = '';
53
54
// Prepare POST variables
55
$post_type = filter_input(INPUT_POST, 'type', FILTER_SANITIZE_STRING);
56
$post_login = filter_input(INPUT_POST, 'login', FILTER_SANITIZE_STRING);
57
$post_pwd = filter_input(INPUT_POST, 'pwd', FILTER_SANITIZE_STRING);
58
$post_sig_response = filter_input(INPUT_POST, 'sig_response', FILTER_SANITIZE_STRING);
59
$post_cardid = filter_input(INPUT_POST, 'cardid', FILTER_SANITIZE_STRING);
60
$post_data = filter_input(INPUT_POST, 'data', FILTER_SANITIZE_STRING, FILTER_FLAG_NO_ENCODE_QUOTES);
61
62
if ($post_type === 'identify_duo_user') {
63
    //--------
64
    // DUO AUTHENTICATION
65
    //--------
66
    // This step creates the DUO request encrypted key
67
68
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
69
    include_once SECUREPATH.'/sk.php';
70
71
    // load library
72
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/DuoSecurity/Duo.php';
73
    $sig_request = Duo::signRequest(IKEY, SKEY, AKEY, $post_login);
74
75
    $dbgDuo = fopen($SETTINGS['path_to_files_folder'].'/duo.debug.txt', 'w');
76
    debugIdentify(
77
        $debugDuo,
78
        $dbgDuo,
0 ignored issues
show
Bug introduced by
$dbgDuo of type false|resource is incompatible with the type string expected by parameter $dbgFile of debugIdentify(). ( Ignorable by Annotation )

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

78
        /** @scrutinizer ignore-type */ $dbgDuo,
Loading history...
79
        "\n\n-----\n\n".
80
            'sig request : '.$post_login."\n".
81
            'resp : '.$sig_request."\n"
82
    );
83
84
    // load csrfprotector
85
    $csrfp_config = include_once $SETTINGS['cpassman_dir'].'/includes/libraries/csrfp/libs/csrfp.config.php';
86
87
    // return result
88
    echo '[{"sig_request" : "'.$sig_request.'" , "csrfp_token" : "'.$csrfp_config['CSRFP_TOKEN'].'" , "csrfp_key" : "'.filter_var($_COOKIE[$csrfp_config['CSRFP_TOKEN']], FILTER_SANITIZE_STRING).'"}]';
89
// DUO Identification
90
} elseif ($post_type === 'identify_duo_user_check') {
91
    //--------
92
    // DUO AUTHENTICATION
93
    // this step is verifying the response received from the server
94
    //--------
95
96
    include $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
97
    include_once SECUREPATH.'/sk.php';
98
99
    // load library
100
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/DuoSecurity/Duo.php';
101
    $resp = Duo::verifyResponse(IKEY, SKEY, AKEY, $post_sig_response);
102
103
    debugIdentify(
104
        $debugDuo,
105
        $dbgDuo,
106
        "\n\n-----\n\n".
107
            'sig response : '.$post_sig_response."\n".
108
            'resp : '.$resp."\n"
109
    );
110
111
    // return the response (which should be the user name)
112
    if ($resp === $post_login) {
113
        // Check if this account exists in Teampass or only in LDAP
114
        if (isset($SETTINGS['ldap_mode']) === true && $SETTINGS['ldap_mode'] === '1') {
115
            include_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
116
            include_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
117
            // connect to the server
118
            include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
119
            $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
120
            $link->set_charset(DB_ENCODING);
121
122
            // is user in Teampass?
123
            $data = DB::queryfirstrow(
124
                'SELECT id
125
                FROM '.prefixTable('users').'
126
                WHERE login = %s',
127
                $post_login
128
            );
129
130
            if (DB::count() === 0) {
131
                // Get LDAP info for this user
132
                $ldap_info_user = json_decode(connectLDAP($post_login, $post_pwd, $SETTINGS));
133
134
                if ($ldap_info_user->{'user_found'} === true && $ldap_info_user->{'auth_success'} === true) {
135
                    // load passwordLib library
136
                    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
137
                    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'].'/includes/libraries');
138
                    $pwdlib->register();
139
                    $pwdlib = new PasswordLib\PasswordLib();
140
141
                    // save an account in database
142
                    DB::insert(
143
                        prefixTable('users'),
144
                        array(
145
                            'login' => $post_login,
146
                            'pw' => $pwdlib->createPasswordHash($post_pwd),
147
                            'email' => $ldap_info_user->{'email'},
148
                            'name' => $ldap_info_user->{'name'},
149
                            'lastname' => $ldap_info_user->{'lastname'},
150
                            'admin' => '0',
151
                            'gestionnaire' => '0',
152
                            'can_manage_all_users' => '0',
153
                            'personal_folder' => $SETTINGS['enable_pf_feature'] === '1' ? '1' : '0',
154
                            'fonction_id' => isset($SETTINGS['ldap_new_user_role']) === true ? $SETTINGS['ldap_new_user_role'] : '0',
155
                            'groupes_interdits' => '',
156
                            'groupes_visibles' => '',
157
                            'last_pw_change' => time(),
158
                            'user_language' => $SETTINGS['default_language'],
159
                            'encrypted_psk' => '',
160
                            '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,
161
                        )
162
                    );
163
                    $newUserId = DB::insertId();
164
                    // Create personnal folder
165
                    if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1') {
166
                        DB::insert(
167
                            prefixTable('nested_tree'),
168
                            array(
169
                                'parent_id' => '0',
170
                                'title' => $newUserId,
171
                                'bloquer_creation' => '0',
172
                                'bloquer_modification' => '0',
173
                                'personal_folder' => '1',
174
                            )
175
                        );
176
                    }
177
                }
178
            }
179
        }
180
181
        echo '[{"resp" : "'.$resp.'"}]';
182
    } else {
183
        echo '[{"resp" : "'.$resp.'"}]';
184
    }
185
} elseif ($post_type === 'identify_user_with_agses') {
186
    //--------
187
    //-- AUTHENTICATION WITH AGSES
188
    //--------
189
190
    include_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
191
    include_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
192
    // connect to the server
193
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
194
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
195
    $link->set_charset(DB_ENCODING);
196
197
    // do checks
198
    if (null !== $post_cardid && empty($post_cardid) === true) {
199
        // no card id is given
200
        // check if it is DB
201
        $row = DB::queryFirstRow(
202
            'SELECT `agses-usercardid` FROM '.prefixTable('users').'
203
            WHERE login = %s',
204
            $post_login
205
        );
206
    } elseif (empty($post_cardid) === false && is_numeric($post_cardid)) {
207
        // card id is given
208
        // save it in DB
209
        DB::update(
210
            prefixTable('users'),
211
            array(
212
                'agses-usercardid' => $post_cardid,
213
                ),
214
            'login = %s',
215
            $post_login
216
        );
217
        $row['agses-usercardid'] = $post_cardid;
218
    } else {
219
        // error
220
        echo '[{"error" : "something_wrong" , "agses_message" : ""}]';
221
222
        return false;
223
    }
224
225
    //-- get AGSES hosted information
226
    $ret_agses_url = DB::queryFirstRow(
227
        'SELECT valeur FROM '.prefixTable('misc').'
228
        WHERE type = %s AND intitule = %s',
229
        'admin',
230
        'agses_hosted_url'
231
    );
232
233
    $ret_agses_id = DB::queryFirstRow(
234
        'SELECT valeur FROM '.prefixTable('misc').'
235
        WHERE type = %s AND intitule = %s',
236
        'admin',
237
        'agses_hosted_id'
238
    );
239
240
    $ret_agses_apikey = DB::queryFirstRow(
241
        'SELECT valeur FROM '.prefixTable('misc').'
242
        WHERE type = %s AND intitule = %s',
243
        'admin',
244
        'agses_hosted_apikey'
245
    );
246
247
    // if we have a card id and all agses credentials
248
    // then we try to generate the message for agsesflicker
249
    if (isset($row['agses-usercardid']) && empty($ret_agses_url['valeur']) === false
250
        && empty($ret_agses_id['valeur']) === false && empty($ret_agses_apikey['valeur']) === false
251
    ) {
252
        // check that card id is not empty or equal to 0
253
        if ($row['agses-usercardid'] !== '0' && !empty($row['agses-usercardid'])) {
254
            include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/agses/axs/AXSILPortal_V1_Auth.php';
255
            $agses = new AXSILPortal_V1_Auth();
256
            $agses->setUrl($ret_agses_url['valeur']);
257
            $agses->setAAId($ret_agses_id['valeur']);
258
            //for release there will be another api-key - this is temporary only
259
            $agses->setApiKey($ret_agses_apikey['valeur']);
260
            $agses->create();
261
            //create random salt and store it into session
262
            if (!isset($_SESSION['hedgeId']) || empty($_SESSION['hedgeId']) === true) {
263
                $_SESSION['hedgeId'] = md5(time());
264
            }
265
            $_SESSION['user_settings']['agses-usercardid'] = $row['agses-usercardid'];
266
            $agses_message = $agses->createAuthenticationMessage(
267
                (string) $row['agses-usercardid'],
268
                true,
269
                1,
270
                2,
271
                (string) $_SESSION['hedgeId']
272
            );
273
274
            echo '[{"agses_message" : "'.$agses_message.'" , "error" : ""}]';
275
        } else {
276
            echo '[{"agses_status" : "no_user_card_id" , "agses_message" : "" , "error" : ""}]';
277
        }
278
    } else {
279
        if (empty($ret_agses_apikey['valeur']) || empty($ret_agses_url['valeur']) || empty($ret_agses_id['valeur'])) {
280
            echo '[{"error" : "no_agses_info" , "agses_message" : ""}]';
281
        } else {
282
            echo '[{"error" : "something_wrong" , "agses_message" : "none" , "agses_status" : "no_user_card_id"}]'; // user not found but not displayed as this in the error message
283
        }
284
    }
285
} elseif ($post_type === 'identify_user') {
286
    //--------
287
    // NORMAL IDENTICATION STEP
288
    //--------
289
290
    // increment counter of login attempts
291
    if (empty($_SESSION['pwd_attempts'])) {
292
        $_SESSION['pwd_attempts'] = 1;
293
    } else {
294
        ++$_SESSION['pwd_attempts'];
295
    }
296
297
    // manage brute force
298
    if ($_SESSION['pwd_attempts'] <= 3) {
299
        // identify the user through Teampass process
300
        identifyUser(
301
            $post_data,
302
            $debugLdap,
303
            $debugDuo,
304
            $SETTINGS
305
        );
306
    } elseif (isset($_SESSION['next_possible_pwd_attempts']) && time() > $_SESSION['next_possible_pwd_attempts'] && $_SESSION['pwd_attempts'] > 3) {
307
        $_SESSION['pwd_attempts'] = 1;
308
        // identify the user through Teampass process
309
        identifyUser(
310
            $post_data,
311
            $debugLdap,
312
            $debugDuo,
313
            $SETTINGS
314
        );
315
    } else {
316
        $_SESSION['next_possible_pwd_attempts'] = time() + 10;
317
318
        // Encrypt data to return
319
        echo json_encode(
320
            array(
321
                'value' => 'bruteforce_wait',
322
                'user_admin' => isset($_SESSION['user_admin']) ? /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['user_admin']) : '',
323
                'initial_url' => @$_SESSION['initial_url'],
324
                'pwd_attempts' => /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['pwd_attempts']),
325
                'error' => 'bruteforce_wait',
326
                'message' => langHdl('error_bad_credentials_more_than_3_times'),
327
            )
328
        );
329
330
        return false;
331
    }
332
} elseif ($post_type === 'store_data_in_cookie') {
333
    //--------
334
    // STORE DATA IN COOKIE
335
    //--------
336
    //
337
    // not used any more (only development purpose)
338
    if ($post_key !== $_SESSION['key']) {
339
        echo '[{"error" : "something_wrong"}]';
340
341
        return false;
342
    }
343
    // store some connection data in cookie
344
    setcookie(
345
        'TeamPassC',
346
        $post_data,
347
        time() + 60 * 60,
348
        '/'
349
    );
350
} elseif ($post_type === 'get2FAMethods') {
351
    //--------
352
    // STORE DATA IN COOKIE
353
    //--------
354
    //
355
    $agses = $duo = $google = $yubico = $nb = 0;
356
    if (isset($SETTINGS['agses_authentication_enabled']) === true && $SETTINGS['agses_authentication_enabled'] === '1') {
357
        $agses = 1;
358
        ++$nb;
359
    }
360
    if (isset($SETTINGS['google_authentication']) === true && $SETTINGS['google_authentication'] === '1') {
361
        $google = 1;
362
        ++$nb;
363
    }
364
    if (isset($SETTINGS['yubico_authentication']) === true && $SETTINGS['yubico_authentication'] === '1') {
365
        $yubico = 1;
366
        ++$nb;
367
    }
368
    if (isset($SETTINGS['duo']) === true && $SETTINGS['duo'] === '1') {
369
        $duo = 1;
370
        ++$nb;
371
    }
372
373
    // Encrypt data to return
374
    echo json_encode(
375
        array(
376
            'agses' => $agses,
377
            'google' => $google,
378
            'yubico' => $yubico,
379
            'duo' => $duo,
380
            'nb' => $nb,
381
        )
382
    );
383
384
    return false;
385
}
386
387
/**
388
 * Complete authentication of user through Teampass.
389
 *
390
 * @param [type] $sentData
0 ignored issues
show
Documentation Bug introduced by
The doc comment [type] at position 0 could not be parsed: Unknown type name '[' at position 0 in [type].
Loading history...
391
 * @param [type] $debugLdap
392
 * @param [type] $debugDuo
393
 * @param [type] $SETTINGS
394
 */
395
function identifyUser($sentData, $debugLdap, $debugDuo, $SETTINGS)
396
{
397
    // Load config
398
    if (file_exists('../includes/config/tp.config.php')) {
399
        include_once '../includes/config/tp.config.php';
400
    } elseif (file_exists('./includes/config/tp.config.php')) {
401
        include_once './includes/config/tp.config.php';
402
    } else {
403
        throw new Exception("Error file '/includes/config/tp.config.php' not exists", 1);
404
    }
405
    include_once $SETTINGS['cpassman_dir'].'/includes/config/settings.php';
406
407
    header('Content-type: text/html; charset=utf-8');
408
    error_reporting(E_ERROR);
409
    include_once $SETTINGS['cpassman_dir'].'/sources/main.functions.php';
410
    include_once $SETTINGS['cpassman_dir'].'/sources/SplClassLoader.php';
411
412
    // Load AntiXSS
413
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
414
    $antiXss = new protect\AntiXSS\AntiXSS();
415
416
    // Load superGlobals
417
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/SuperGlobal/SuperGlobal.php';
418
    $superGlobal = new protect\SuperGlobal\SuperGlobal();
419
420
    // Prepare GET variables
421
    $session_user_language = $superGlobal->get('user_language', 'SESSION');
422
423
    // Debug
424
    $dbgDuo = fopen($SETTINGS['path_to_files_folder'].'/duo.debug.txt', 'a');
425
    debugIdentify(
426
        $debugDuo,
427
        $dbgDuo,
0 ignored issues
show
Bug introduced by
$dbgDuo of type false|resource is incompatible with the type string expected by parameter $dbgFile of debugIdentify(). ( Ignorable by Annotation )

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

427
        /** @scrutinizer ignore-type */ $dbgDuo,
Loading history...
428
        "Content of data sent '".filter_var($sentData, FILTER_SANITIZE_STRING)."'\n"
429
    );
430
431
    // connect to the server
432
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Database/Meekrodb/db.class.php';
433
    DB::$host = DB_HOST;
434
    DB::$user = DB_USER;
435
    DB::$password = defuseReturnDecrypted(DB_PASSWD, $SETTINGS);
436
    DB::$dbName = DB_NAME;
437
    DB::$port = DB_PORT;
438
    DB::$encoding = DB_ENCODING;
439
    $link = mysqli_connect(DB_HOST, DB_USER, defuseReturnDecrypted(DB_PASSWD, $SETTINGS), DB_NAME, DB_PORT);
440
    $link->set_charset(DB_ENCODING);
441
442
    // load passwordLib library
443
    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'].'/includes/libraries');
444
    $pwdlib->register();
445
    $pwdlib = new PasswordLib\PasswordLib();
446
447
    // User's language loading
448
    include_once $SETTINGS['cpassman_dir'].'/includes/language/'.$session_user_language.'.php';
449
450
    // decrypt and retreive data in JSON format
451
    $dataReceived = prepareExchangedData($sentData, 'decode', $_SESSION['key']);
452
    //print_r($dataReceived);
453
454
    // prepare variables
455
    if (isset($SETTINGS['enable_http_request_login']) === true
456
        && $SETTINGS['enable_http_request_login'] === '1'
457
        && isset($_SERVER['PHP_AUTH_USER']) === true
458
        && isset($SETTINGS['maintenance_mode']) === true
459
        && $SETTINGS['maintenance_mode'] === '1'
460
    ) {
461
        if (strpos($_SERVER['PHP_AUTH_USER'], '@') !== false) {
462
            $username = explode('@', filter_var($_SERVER['PHP_AUTH_USER'], FILTER_SANITIZE_STRING))[0];
463
        } elseif (strpos($_SERVER['PHP_AUTH_USER'], '\\') !== false) {
464
            $username = explode('\\', filter_var($_SERVER['PHP_AUTH_USER'], FILTER_SANITIZE_STRING))[1];
465
        } else {
466
            $username = filter_var($_SERVER['PHP_AUTH_USER'], FILTER_SANITIZE_STRING);
467
        }
468
        $passwordClear = $_SERVER['PHP_AUTH_PW'];
469
        $usernameSanitized = '';
470
    } else {
471
        $passwordClear = $dataReceived['pw'];
472
        $username = $dataReceived['login'];
473
        $usernameSanitized = $antiXss->xss_clean(htmlspecialchars_decode($dataReceived['login_sanitized']));
474
    }
475
476
    // User's 2FA method
477
    $user_2fa_selection = $antiXss->xss_clean(htmlspecialchars_decode($dataReceived['user_2fa_selection']));
478
479
    // User's agses code
480
    $user_agses_code = $antiXss->xss_clean(htmlspecialchars_decode($dataReceived['agses_code']));
0 ignored issues
show
Unused Code introduced by
The assignment to $user_agses_code is dead and can be removed.
Loading history...
481
482
    // Check 2FA
483
    if ((($SETTINGS['yubico_authentication'] === '1' && empty($user_2fa_selection) === true)
484
        || ($SETTINGS['google_authentication'] === '1' && empty($user_2fa_selection) === true))
485
        && ($username !== 'admin' || ((int) $SETTINGS['admin_2fa_required'] === 1 && $username === 'admin'))
486
    ) {
487
        echo json_encode(
488
            array(
489
                'value' => '2fa_not_set',
490
                'user_admin' => isset($_SESSION['user_admin']) ? /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['user_admin']) : '',
491
                'initial_url' => @$_SESSION['initial_url'],
492
                'pwd_attempts' => /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['pwd_attempts']),
493
                'error' => '2fa_not_set',
494
                'message' => langHdl('2fa_credential_not_correct'),
495
            )
496
        );
497
498
        return;
499
    }
500
501
    // Debug
502
    debugIdentify(
503
        $debugDuo,
504
        $dbgDuo,
505
        "Starting authentication of '".$username."'\n".
506
        'LDAP status: '.$SETTINGS['ldap_mode']."\n"
507
    );
508
    $dbgLdap = fopen($SETTINGS['path_to_files_folder'].'/ldap.debug.txt', 'w');
509
    debugIdentify(
510
        $debugLdap,
511
        $dbgLdap,
512
        "Get all LDAP params : \n".
513
            'mode : '.$SETTINGS['ldap_mode']."\n".
514
            'type : '.$SETTINGS['ldap_type']."\n".
515
            'base_dn : '.$SETTINGS['ldap_domain_dn']."\n".
516
            'search_base : '.$SETTINGS['ldap_search_base']."\n".
517
            'bind_dn : '.$SETTINGS['ldap_bind_dn']."\n".
518
            'bind_passwd : '.$SETTINGS['ldap_bind_passwd']."\n".
519
            'user_attribute : '.$SETTINGS['ldap_user_attribute']."\n".
520
            'account_suffix : '.$SETTINGS['ldap_suffix']."\n".
521
            'domain_controllers : '.$SETTINGS['ldap_domain_controler']."\n".
522
            'ad_port : '.$SETTINGS['ldap_port']."\n".
523
            'use_ssl : '.$SETTINGS['ldap_ssl']."\n".
524
            'use_tls : '.$SETTINGS['ldap_tls']."\n*********\n\n"
525
    );
526
527
    // Check if user exists
528
    $data = DB::queryFirstRow(
529
        'SELECT * FROM '.prefixTable('users').' WHERE login=%s_login',
530
        array(
531
            'login' => $username,
532
        )
533
    );
534
    $counter = DB::count();
535
536
    // 2.1.27.24 - in case of login encoding error
537
    if ($counter === 0) {
538
        // Test
539
        $data = DB::queryFirstRow(
540
            'SELECT * FROM '.prefixTable('users').' WHERE login=%s_login',
541
            array(
542
                'login' => $usernameSanitized,
543
            )
544
        );
545
        $counter = DB::count();
546
        if ($counter === 1) {
547
            // Adapt in DB
548
            DB::update(
549
                prefixTable('users'),
550
                array(
551
                    'login' => $username,
552
                ),
553
                'id=%i',
554
                $data['id']
555
            );
556
            $data['login'] = $username;
557
        }
558
    }
559
560
    // Debug
561
    debugIdentify(
562
        $debugDuo,
563
        $dbgDuo,
564
        'USer exists: '.$counter."\n"
565
    );
566
567
    $user_initial_creation_through_ldap = false;
568
    $proceedIdentification = false;
569
    $userPasswordVerified = false;
570
    $ldapConnection = false;
571
    $logError = array();
572
    $user_info_from_ad = '';
573
574
    // Prepare LDAP connection if set up
575
    if (isset($SETTINGS['ldap_mode'])
576
        && $SETTINGS['ldap_mode'] === '1'
577
        && $username !== 'admin'
578
    ) {
579
        //Multiple Domain Names
580
        if (strpos(html_entity_decode($username), '\\') === true) {
581
            $ldap_suffix = '@'.substr(html_entity_decode($username), 0, strpos(html_entity_decode($username), '\\'));
582
            $username = substr(html_entity_decode($username), strpos(html_entity_decode($username), '\\') + 1);
583
        }
584
        if ($SETTINGS['ldap_type'] === 'posix-search') {
585
            $ret = identifyViaLDAPPosixSearch(
586
                $username,
587
                $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...
588
                $passwordClear,
589
                $SETTINGS
590
            );
591
592
            if ($ret['error'] === true) {
593
                echo json_encode($ret['message']);
594
            } else {
595
                $ldapConnection = true;
596
                $user_info_from_ad = $ret['user_info_from_ad'];
597
                $proceedIdentification = $ret['proceedIdentification'];
598
            }
599
        } else {
600
            $ret = identifyViaLDAPPosix(
601
                $username,
602
                $ldap_suffix,
603
                $passwordClear,
604
                $SETTINGS
605
            );
606
607
            if ($ret['error'] === true) {
0 ignored issues
show
introduced by
The condition $ret['error'] === true is always false.
Loading history...
608
                echo json_encode($ret['message']);
609
            } else {
610
                $auth_username = $ret['auth_username'];
0 ignored issues
show
Unused Code introduced by
The assignment to $auth_username is dead and can be removed.
Loading history...
611
                $proceedIdentification = $ret['proceedIdentification'];
612
                $user_info_from_ad = $ret['user_info_from_ad'];
613
            }
614
        }
615
    }
616
617
    // Check Yubico
618
    if (isset($SETTINGS['yubico_authentication'])
619
        && $SETTINGS['yubico_authentication'] === '1'
620
        && ($data['admin'] !== '1' || ((int) $SETTINGS['admin_2fa_required'] === 1 && $data['admin'] === '1'))
621
        && $user_2fa_selection === 'yubico'
622
    ) {
623
        $ret = yubicoMFACheck(
624
            $username,
625
            $ldap_suffix,
626
            $dataReceived,
627
            $data,
628
            $SETTINGS
629
        );
630
631
        if ($ret['error'] === true) {
632
            echo json_encode($ret['message']);
633
634
            return;
635
        } else {
636
            $proceedIdentification = $ret['proceedIdentification'];
637
        }
638
    }
639
640
    // Create new LDAP user if not existing in Teampass
641
    // Don't create it if option "only localy declared users" is enabled
642
    if ($counter == 0 && $ldapConnection === true && isset($SETTINGS['ldap_elusers'])
643
        && ($SETTINGS['ldap_elusers'] == 0)
644
    ) {
645
        // If LDAP enabled, create user in TEAMPASS if doesn't exist
646
647
        /*// Get user info from LDAP
648
        if ($SETTINGS['ldap_type'] === 'posix-search') {
649
            //Because we didn't use adLDAP, we need to set the user info from the ldap_get_entries result
650
            $user_info_from_ad = $result;
651
        } else {
652
            $user_info_from_ad = $adldap->user()->info($auth_username, array('mail', 'givenname', 'sn'));
653
        }*/
654
        $ret = ldapCreateUser(
655
            $username,
656
            $data,
657
            $user_info_from_ad,
658
            $SETTINGS
659
        );
660
661
        if ($ret['error'] === true) {
0 ignored issues
show
introduced by
The condition $ret['error'] === true is always false.
Loading history...
662
            echo json_encode($ret['message']);
663
664
            return;
665
        } else {
666
            $proceedIdentification = $ret['proceedIdentification'];
667
            $user_initial_creation_through_ldap = $ret['user_initial_creation_through_ldap'];
668
        }
669
    }
670
671
    // Check if user exists (and has been created in case of new LDAP user)
672
    $data = DB::queryFirstRow(
673
        'SELECT * FROM '.prefixTable('users').' WHERE login=%s_login',
674
        array(
675
            'login' => $username,
676
        )
677
    );
678
    $counter = DB::count();
679
    if ($counter === 0) {
680
        logEvents('failed_auth', 'user_not_exists', '', stripslashes($username), stripslashes($username));
681
        echo json_encode(
682
            array(
683
                'value' => '',
684
                'user_admin' => isset($_SESSION['user_admin']) ? (int) $_SESSION['user_admin'] : '',
685
                'initial_url' => isset($_SESSION['initial_url']) === true ? $_SESSION['initial_url'] : '',
686
                'pwd_attempts' => (int) $_SESSION['pwd_attempts'],
687
                'error' => 'user_not_exists',
688
                'message' => langHdl('error_bad_credentials'),
689
            )
690
        );
691
692
        return;
693
    }
694
695
    // check GA code
696
    if (isset($SETTINGS['google_authentication']) === true
697
        && $SETTINGS['google_authentication'] === '1'
698
        && ($username !== 'admin' || ((int) $SETTINGS['admin_2fa_required'] === 1 && $username === 'admin'))
699
        && $user_2fa_selection === 'google'
700
    ) {
701
        $ret = GoogleMFACheck(
702
            $data,
703
            $dataReceived,
704
            $SETTINGS
705
        );
706
707
        if ($ret['error'] === true) {
708
            echo json_encode($ret['message']);
709
710
            return;
711
        } else {
712
            $proceedIdentification = $ret['proceedIdentification'];
713
            $user_initial_creation_through_ldap = $ret['user_initial_creation_through_ldap'];
714
715
            // Manage 1st usage of Google MFA
716
            if (count($ret['firstTime']) > 0) {
717
                echo json_encode($ret['firstTime']);
718
719
                return;
720
            }
721
        }
722
    } elseif ($counter > 0) {
723
        $proceedIdentification = true;
724
    }
725
726
    // Debug
727
    debugIdentify(
728
        $debugDuo,
729
        $dbgDuo,
730
        'Proceed with Ident: '.$proceedIdentification."\n"
731
    );
732
733
    /*
734
    // check AGSES code
735
    if (isset($SETTINGS['agses_authentication_enabled']) === true
736
        && $SETTINGS['agses_authentication_enabled'] === '1'
737
        && ($username !== 'admin' || ((int) $SETTINGS['admin_2fa_required'] === 1 && $username === 'admin'))
738
        && $user_2fa_selection === 'agses'
739
        && empty($user_agses_code) === false
740
    ) {
741
        // load AGSES
742
        include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/agses/axs/AXSILPortal_V1_Auth.php';
743
        $agses = new AXSILPortal_V1_Auth();
744
        $agses->setUrl($SETTINGS['agses_hosted_url']);
745
        $agses->setAAId($SETTINGS['agses_hosted_id']);
746
        //for release there will be another api-key - this is temporary only
747
        $agses->setApiKey($SETTINGS['agses_hosted_apikey']);
748
        $agses->create();
749
        //create random salt and store it into session
750
        if (!isset($_SESSION['hedgeId']) || $_SESSION['hedgeId'] == '') {
751
            $_SESSION['hedgeId'] = md5(time());
752
        }
753
754
        $responseCode = $user_agses_code;
755
        if ($responseCode != '' && strlen($responseCode) >= 4) {
756
            // Verify response code, store result in session
757
            $result = $agses->verifyResponse(
758
                (string) $_SESSION['user_settings']['agses-usercardid'],
759
                $responseCode,
760
                (string) $_SESSION['hedgeId']
761
            );
762
763
            if ($result == 1) {
764
                $return = '';
765
                $proceedIdentification = true;
766
                $userPasswordVerified = false;
767
                unset($_SESSION['hedgeId']);
768
                unset($_SESSION['flickercode']);
769
            } else {
770
                if ($result < -10) {
771
                    $logError = array(
772
                        'error' => 'agses_error',
773
                        'message' => 'ERROR: '.$result,
774
                    );
775
                } elseif ($result == -4) {
776
                    $logError = array(
777
                        'error' => 'agses_error',
778
                        'message' => 'Wrong response code, no more tries left.',
779
                    );
780
                } elseif ($result == -3) {
781
                    $logError = array(
782
                        'error' => 'agses_error',
783
                        'message' => 'Wrong response code, try to reenter.',
784
                    );
785
                } elseif ($result == -2) {
786
                    $logError = array(
787
                        'error' => 'agses_error',
788
                        'message' => 'Timeout. The response code is not valid anymore.',
789
                    );
790
                } elseif ($result == -1) {
791
                    $logError = array(
792
                        'error' => 'agses_error',
793
                        'message' => 'Security Error. Did you try to verify the response from a different computer?',
794
                    );
795
                } elseif ($result == 1) {
796
                    $logError = array(
797
                        'error' => 'agses_error',
798
                        'message' => 'Authentication successful, response code correct.<br /><br />Authentification Method for SecureBrowser updated!',
799
                    );
800
                }
801
                echo json_encode(
802
                    array(
803
                        'value' => '',
804
                        'user_admin' => isset($_SESSION['user_admin']) ? (int) $_SESSION['user_admin'] : '',
805
                        'initial_url' => @$_SESSION['initial_url'],
806
                        'pwd_attempts' => (int) $_SESSION['pwd_attempts'],
807
                        'error' => $logError['error'],
808
                        'message' => $logError['message'],
809
                    )
810
                );
811
812
                return;
813
            }
814
        } else {
815
            echo json_encode(
816
                array(
817
                    'value' => '',
818
                    'user_admin' => isset($_SESSION['user_admin']) ? (int) $_SESSION['user_admin'] : '',
819
                    'initial_url' => @$_SESSION['initial_url'],
820
                    'pwd_attempts' => (int) $_SESSION['pwd_attempts'],
821
                    'error' => 'agses_error',
822
                    'message' => 'No response code given',
823
                )
824
            );
825
826
            return;
827
        }
828
    }
829
    */
830
831
    // If admin user then check if folder install exists
832
    // if yes then refuse connection
833
    if ($data['admin'] === '1' && is_dir('../install')) {
834
        echo json_encode(
835
            array(
836
                'value' => '',
837
                'user_admin' => isset($_SESSION['user_admin']) ? /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['user_admin']) : '',
838
                'initial_url' => @$_SESSION['initial_url'],
839
                'pwd_attempts' => /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['pwd_attempts']),
840
                'error' => 'install_error',
841
                'message' => 'Install folder has to be removed!',
842
            )
843
        );
844
845
        return;
846
    }
847
848
    if ($proceedIdentification === true) {
849
        // User exists in the DB
850
        if (crypt($passwordClear, $data['pw']) === $data['pw']
851
            && empty($data['pw']) === false
852
        ) {
853
            //update user's password
854
            $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
855
            DB::update(
856
                prefixTable('users'),
857
                array(
858
                    'pw' => $data['pw'],
859
                ),
860
                'id=%i',
861
                $data['id']
862
            );
863
        }
864
865
        // check the given password
866
        if ($userPasswordVerified !== true) {
0 ignored issues
show
introduced by
The condition $userPasswordVerified !== true is always true.
Loading history...
867
            if ($pwdlib->verifyPasswordHash($passwordClear, $data['pw']) === true) {
868
                $userPasswordVerified = true;
869
            } else {
870
                // 2.1.27.24 - manage passwords
871
                $passwordClearSanitized = htmlspecialchars_decode($dataReceived['pw_sanitized']);
872
873
                if ($pwdlib->verifyPasswordHash($passwordClearSanitized, $data['pw']) === true) {
874
                    // then the auth is correct but needs to be adapted in DB since change of encoding
875
                    $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
876
                    DB::update(
877
                        prefixTable('users'),
878
                        array(
879
                            'pw' => $data['pw'],
880
                        ),
881
                        'id=%i',
882
                        $data['id']
883
                    );
884
                } else {
885
                    $userPasswordVerified = false;
886
                    logEvents(
887
                        'failed_auth',
888
                        'user_password_not_correct',
889
                        '',
890
                        '',
891
                        stripslashes($username)
892
                    );
893
                }
894
            }
895
        }
896
897
        // Debug
898
        debugIdentify(
899
            $debugDuo,
900
            $dbgDuo,
901
            "User's password verified: ".$userPasswordVerified."\n"
902
        );
903
904
        // Can connect if
905
        // 1- no LDAP mode + user enabled + pw ok
906
        // 2- LDAP mode + user enabled + ldap connection ok + user is not admin
907
        // 3-  LDAP mode + user enabled + pw ok + usre is admin
908
        // This in order to allow admin by default to connect even if LDAP is activated
909
        if ((isset($SETTINGS['ldap_mode']) === true && $SETTINGS['ldap_mode'] === '0'
910
            && $userPasswordVerified === true && $data['disabled'] === '0')
911
            || (isset($SETTINGS['ldap_mode']) === true && $SETTINGS['ldap_mode'] === '1'
912
            && $ldapConnection === true && $data['disabled'] === '0' && $username !== 'admin')
913
            || (isset($SETTINGS['ldap_mode']) === true && $SETTINGS['ldap_mode'] === '2'
914
            && $ldapConnection === true && $data['disabled'] === '0' && $username !== 'admin')
915
            || (isset($SETTINGS['ldap_mode']) === true && $SETTINGS['ldap_mode'] === '1'
916
            && $username == 'admin' && $userPasswordVerified === true && $data['disabled'] === '0')
917
            || (isset($SETTINGS['ldap_and_local_authentication']) === true && $SETTINGS['ldap_and_local_authentication'] === '1'
918
            && isset($SETTINGS['ldap_mode']) === true && in_array($SETTINGS['ldap_mode'], array('1', '2')) === true
919
            && $userPasswordVerified === true && $data['disabled'] === '0')
920
        ) {
921
            $_SESSION['autoriser'] = true;
922
            $_SESSION['pwd_attempts'] = 0;
923
924
            // Generate a ramdom ID
925
            $key = GenerateCryptKey(50);
926
927
            // Debug
928
            debugIdentify(
929
                $debugDuo,
930
                $dbgDuo,
931
                "User's token: ".$key."\n"
932
            );
933
934
            // Check if any unsuccessfull login tries exist
935
            $arrAttempts = array();
936
            $rows = DB::query(
937
                'SELECT date
938
                FROM '.prefixTable('log_system')."
939
                WHERE field_1 = %s
940
                AND type = 'failed_auth'
941
                AND label = 'user_password_not_correct'
942
                AND date >= %s AND date < %s",
943
                $data['login'],
944
                $data['last_connexion'],
945
                time()
946
            );
947
            $arrAttempts['nb'] = DB::count();
948
            $arrAttempts['shown'] = false;
949
            $arrAttempts['attempts'] = array();
950
            if (DB::count() > 0) {
951
                foreach ($rows as $record) {
952
                    array_push(
953
                        $arrAttempts['attempts'],
954
                        date($SETTINGS['date_format'].' '.$SETTINGS['time_format'], $record['date'])
955
                    );
956
                }
957
            }
958
            $_SESSION['unsuccessfull_login_attempts'] = $arrAttempts;
959
960
            // Log into DB the user's connection
961
            if (isset($SETTINGS['log_connections']) === true
962
                && (int) $SETTINGS['log_connections'] === 1
963
            ) {
964
                logEvents('user_connection', 'connection', $data['id'], stripslashes($username));
965
            }
966
            // Save account in SESSION
967
            $_SESSION['login'] = stripslashes($username);
968
            $_SESSION['name'] = stripslashes($data['name']);
969
            $_SESSION['lastname'] = stripslashes($data['lastname']);
970
            $_SESSION['user_id'] = $data['id'];
971
            $_SESSION['user_admin'] = $data['admin'];
972
            $_SESSION['user_manager'] = $data['gestionnaire'];
973
            $_SESSION['user_can_manage_all_users'] = $data['can_manage_all_users'];
974
            $_SESSION['user_read_only'] = $data['read_only'];
975
            $_SESSION['last_pw_change'] = $data['last_pw_change'];
976
            $_SESSION['last_pw'] = $data['last_pw'];
977
            $_SESSION['can_create_root_folder'] = $data['can_create_root_folder'];
978
            $_SESSION['key'] = $key;
979
            $_SESSION['personal_folder'] = $data['personal_folder'];
980
            $_SESSION['user_language'] = $data['user_language'];
981
            $_SESSION['user_email'] = $data['email'];
982
            $_SESSION['user_ga'] = $data['ga'];
983
            $_SESSION['user_avatar'] = $data['avatar'];
984
            $_SESSION['user_avatar_thumb'] = $data['avatar_thumb'];
985
            $_SESSION['user_upgrade_needed'] = $data['upgrade_needed'];
986
            $_SESSION['user_force_relog'] = $data['force-relog'];
987
            // get personal settings
988
            if (!isset($data['treeloadstrategy']) || empty($data['treeloadstrategy'])) {
989
                $data['treeloadstrategy'] = 'full';
990
            }
991
            $_SESSION['user_settings']['treeloadstrategy'] = $data['treeloadstrategy'];
992
            $_SESSION['user_settings']['agses-usercardid'] = $data['agses-usercardid'];
993
            $_SESSION['user_settings']['user_language'] = $data['user_language'];
994
            $_SESSION['user_settings']['encrypted_psk'] = $data['encrypted_psk'];
995
            $_SESSION['user_settings']['usertimezone'] = $data['usertimezone'];
996
            $_SESSION['user_settings']['session_duration'] = $dataReceived['duree_session'] * 60;
997
            $_SESSION['user_settings']['api-key'] = $data['user_api_key'];
998
999
            // manage session expiration
1000
            $_SESSION['fin_session'] = (int) (time() + $_SESSION['user_settings']['session_duration']);
1001
1002
            /*
1003
            * CHECK PASSWORD VALIDITY
1004
            * Don't take into consideration if LDAP in use
1005
            */
1006
            if (isset($SETTINGS['ldap_mode']) === true && $SETTINGS['ldap_mode'] === '1') {
1007
                $_SESSION['validite_pw'] = true;
1008
                $_SESSION['last_pw_change'] = true;
1009
            } else {
1010
                if (isset($data['last_pw_change']) === true) {
1011
                    if ($SETTINGS['pw_life_duration'] === '0') {
1012
                        $_SESSION['numDaysBeforePwExpiration'] = 'infinite';
1013
                        $_SESSION['validite_pw'] = true;
1014
                    } else {
1015
                        $_SESSION['numDaysBeforePwExpiration'] = $SETTINGS['pw_life_duration'] - round(
1016
                            (mktime(0, 0, 0, (int) date('m'), (int) date('d'), (int) date('y')) - $_SESSION['last_pw_change']) / (24 * 60 * 60)
1017
                        );
1018
                        if ($_SESSION['numDaysBeforePwExpiration'] <= 0) {
1019
                            $_SESSION['validite_pw'] = false;
1020
                        } else {
1021
                            $_SESSION['validite_pw'] = true;
1022
                        }
1023
                    }
1024
                } else {
1025
                    $_SESSION['validite_pw'] = false;
1026
                }
1027
            }
1028
1029
            /* If this option is set user password MD5 is used as personal SALTKey */
1030
            if (isset($SETTINGS['use_md5_password_as_salt']) &&
1031
                $SETTINGS['use_md5_password_as_salt'] == 1
1032
            ) {
1033
                $_SESSION['user_settings']['clear_psk'] = md5($passwordClear);
1034
                $tmp = encrypt($_SESSION['user_settings']['clear_psk'], '');
1035
                if ($tmp !== false) {
1036
                    setcookie(
1037
                        'TeamPass_PFSK_'.md5($_SESSION['user_id']),
1038
                        $tmp,
1039
                        time() + 60 * 60 * 24 * $SETTINGS['personal_saltkey_cookie_duration'],
1040
                        '/'
1041
                    );
1042
                }
1043
            }
1044
1045
            if (empty($data['last_connexion'])) {
1046
                $_SESSION['derniere_connexion'] = time();
1047
            } else {
1048
                $_SESSION['derniere_connexion'] = $data['last_connexion'];
1049
            }
1050
1051
            if (!empty($data['latest_items'])) {
1052
                $_SESSION['latest_items'] = explode(';', $data['latest_items']);
1053
            } else {
1054
                $_SESSION['latest_items'] = array();
1055
            }
1056
            if (!empty($data['favourites'])) {
1057
                $_SESSION['favourites'] = explode(';', $data['favourites']);
1058
            } else {
1059
                $_SESSION['favourites'] = array();
1060
            }
1061
1062
            if (!empty($data['groupes_visibles'])) {
1063
                $_SESSION['groupes_visibles'] = @implode(';', $data['groupes_visibles']);
1064
            } else {
1065
                $_SESSION['groupes_visibles'] = array();
1066
            }
1067
            if (!empty($data['groupes_interdits'])) {
1068
                $_SESSION['groupes_interdits'] = @implode(';', $data['groupes_interdits']);
1069
            } else {
1070
                $_SESSION['groupes_interdits'] = array();
1071
            }
1072
            // User's roles
1073
            $_SESSION['fonction_id'] = $data['fonction_id'];
1074
            $_SESSION['user_roles'] = explode(';', $data['fonction_id']);
1075
            // build array of roles
1076
            $_SESSION['user_pw_complexity'] = 0;
1077
            $_SESSION['arr_roles'] = array();
1078
            foreach (array_filter(explode(';', $_SESSION['fonction_id'])) as $role) {
1079
                $resRoles = DB::queryFirstRow('SELECT title, complexity FROM '.prefixTable('roles_title').' WHERE id=%i', $role);
1080
                $_SESSION['arr_roles'][$role] = array(
1081
                        'id' => $role,
1082
                        'title' => $resRoles['title'],
1083
                );
1084
                // get highest complexity
1085
                if ($_SESSION['user_pw_complexity'] < $resRoles['complexity']) {
1086
                    $_SESSION['user_pw_complexity'] = $resRoles['complexity'];
1087
                }
1088
            }
1089
            // build complete array of roles
1090
            $_SESSION['arr_roles_full'] = array();
1091
            $rows = DB::query('SELECT id, title FROM '.prefixTable('roles_title').' ORDER BY title ASC');
1092
            foreach ($rows as $record) {
1093
                $_SESSION['arr_roles_full'][$record['id']] = array(
1094
                        'id' => $record['id'],
1095
                        'title' => $record['title'],
1096
                );
1097
            }
1098
            // Set some settings
1099
            $_SESSION['user']['find_cookie'] = false;
1100
            $SETTINGS['update_needed'] = '';
1101
            // Update table
1102
            DB::update(
1103
                prefixTable('users'),
1104
                array(
1105
                    'key_tempo' => $_SESSION['key'],
1106
                    'last_connexion' => time(),
1107
                    'timestamp' => time(),
1108
                    'disabled' => 0,
1109
                    'no_bad_attempts' => 0,
1110
                    'session_end' => $_SESSION['fin_session'],
1111
                    'user_ip' => $dataReceived['client'],
1112
                ),
1113
                'id=%i',
1114
                $data['id']
1115
            );
1116
1117
            // Debug
1118
            debugIdentify(
1119
                $debugDuo,
1120
                $dbgDuo,
1121
                "Preparing to identify the user rights\n"
1122
            );
1123
1124
            // Get user's rights
1125
            if ($user_initial_creation_through_ldap === false) {
1126
                identifyUserRights(
1127
                    $data['groupes_visibles'],
1128
                    $_SESSION['groupes_interdits'],
1129
                    $data['admin'],
1130
                    $data['fonction_id'],
1131
                    $SETTINGS
1132
                );
1133
            } else {
1134
                // is new LDAP user. Show only his personal folder
1135
                if ($SETTINGS['enable_pf_feature'] === '1') {
1136
                    $_SESSION['personal_visible_groups'] = array($data['id']);
1137
                    $_SESSION['personal_folders'] = array($data['id']);
1138
                } else {
1139
                    $_SESSION['personal_visible_groups'] = array();
1140
                    $_SESSION['personal_folders'] = array();
1141
                }
1142
                $_SESSION['all_non_personal_folders'] = array();
1143
                $_SESSION['groupes_visibles'] = array();
1144
                $_SESSION['groupes_visibles_list'] = '';
1145
                $_SESSION['read_only_folders'] = array();
1146
                $_SESSION['list_folders_limited'] = '';
1147
                $_SESSION['list_folders_editable_by_role'] = array();
1148
                $_SESSION['list_restricted_folders_for_items'] = array();
1149
                $_SESSION['nb_folders'] = 1;
1150
                $_SESSION['nb_roles'] = 0;
1151
            }
1152
            // Get some more elements
1153
            $_SESSION['screenHeight'] = $dataReceived['screenHeight'];
1154
            // Get last seen items
1155
            $_SESSION['latest_items_tab'][] = '';
1156
            foreach ($_SESSION['latest_items'] as $item) {
1157
                if (!empty($item)) {
1158
                    $data = DB::queryFirstRow('SELECT id,label,id_tree FROM '.prefixTable('items').' WHERE id=%i', $item);
1159
                    $_SESSION['latest_items_tab'][$item] = array(
1160
                        'id' => $item,
1161
                        'label' => $data['label'],
1162
                        'url' => 'index.php?page=items&amp;group='.$data['id_tree'].'&amp;id='.$item,
1163
                    );
1164
                }
1165
            }
1166
            // send back the random key
1167
            $return = $dataReceived['randomstring'];
1168
            // Send email
1169
            if (isset($SETTINGS['enable_send_email_on_user_login'])
1170
                && $SETTINGS['enable_send_email_on_user_login'] === '1'
1171
                && $_SESSION['user_admin'] != 1
1172
            ) {
1173
                // get all Admin users
1174
                $receivers = '';
1175
                $rows = DB::query('SELECT email FROM '.prefixTable('users')." WHERE admin = %i and email != ''", 1);
1176
                foreach ($rows as $record) {
1177
                    if (empty($receivers)) {
1178
                        $receivers = $record['email'];
1179
                    } else {
1180
                        $receivers = ','.$record['email'];
1181
                    }
1182
                }
1183
                // Add email to table
1184
                DB::insert(
1185
                    prefixTable('emails'),
1186
                    array(
1187
                        'timestamp' => time(),
1188
                        '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...
1189
                        'body' => str_replace(
1190
                            array(
1191
                                '#tp_user#',
1192
                                '#tp_date#',
1193
                                '#tp_time#',
1194
                            ),
1195
                            array(
1196
                                ' '.$_SESSION['login'].' (IP: '.getClientIpServer().')',
1197
                                date($SETTINGS['date_format'], $_SESSION['derniere_connexion']),
1198
                                date($SETTINGS['time_format'], $_SESSION['derniere_connexion']),
1199
                            ),
1200
                            $LANG['email_body_on_user_login']
1201
                        ),
1202
                        'receivers' => $receivers,
1203
                        'status' => 'not_sent',
1204
                    )
1205
                );
1206
            }
1207
        } elseif ($data['disabled'] == 1) {
1208
            // User and password is okay but account is locked
1209
            $logError = array(
1210
                'error' => 'user_is_locked',
1211
                'message' => langHdl('account_is_locked'),
1212
            );
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
                prefixTable('users'),
1231
                array(
1232
                    'key_tempo' => $_SESSION['key'],
1233
                    'disabled' => $userIsLocked,
1234
                    'no_bad_attempts' => $nbAttempts,
1235
                ),
1236
                'id=%i',
1237
                $data['id']
1238
            );
1239
            // What return shoulb we do
1240
            if ($userIsLocked == 1) {
1241
                $logError = array(
1242
                    'error' => 'user_is_locked',
1243
                    'message' => langHdl('account_is_locked'),
1244
                );
1245
            } elseif ($SETTINGS['nb_bad_authentication'] === '0') {
1246
                $logError = array(
1247
                    'error' => 'user_not_exists1',
1248
                    'message' => langHdl('error_bad_credentials'),
1249
                );
1250
            } else {
1251
                $logError = array(
1252
                    'error' => 'user_not_exists2',
1253
                    'message' => langHdl('error_bad_credentials'),
1254
                );
1255
            }
1256
        }
1257
    } else {
1258
        if ($user_initial_creation_through_ldap === true) {
1259
            $return = 'new_ldap_account_created';
1260
        } else {
1261
            $logError = array(
1262
                'error' => 'user_not_exists3',
1263
                'message' => langHdl('error_bad_credentials'),
1264
            );
1265
        }
1266
    }
1267
1268
    // Debug
1269
    debugIdentify(
1270
        $debugDuo,
1271
        $dbgDuo,
1272
        "\n\n----\n".
1273
        'Identified : '.filter_var($return, FILTER_SANITIZE_STRING)."\n\n"
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $return does not seem to be defined for all execution paths leading up to this point.
Loading history...
1274
    );
1275
1276
    // manage bruteforce
1277
    if ($_SESSION['pwd_attempts'] > 2) {
1278
        $_SESSION['next_possible_pwd_attempts'] = time() + 10;
1279
    }
1280
1281
    // Ensure Complexity levels are translated
1282
    if (defined('TP_PW_COMPLEXITY') === false) {
1283
        define(
1284
            'TP_PW_COMPLEXITY',
1285
            array(
1286
                0 => array(0, langHdl('complex_level0'), 'fas fa-bolt text-danger'),
1287
                25 => array(25, langHdl('complex_level1'), 'fas fa-thermometer-empty text-danger'),
1288
                50 => array(50, langHdl('complex_level2'), 'fas fa-thermometer-quarter text-warning'),
1289
                60 => array(60, langHdl('complex_level3'), 'fas fa-thermometer-half text-warning'),
1290
                70 => array(70, langHdl('complex_level4'), 'fas fa-thermometer-three-quarters text-success'),
1291
                80 => array(80, langHdl('complex_level5'), 'fas fa-thermometer-full text-success'),
1292
                90 => array(90, langHdl('complex_level6'), 'far fa-gem text-success'),
1293
            )
1294
        );
1295
    }
1296
1297
    echo json_encode(
1298
        array(
1299
            'value' => $return,
1300
            'user_admin' => isset($_SESSION['user_admin']) ? /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['user_admin']) : '',
1301
            'initial_url' => @$_SESSION['initial_url'],
1302
            'pwd_attempts' => /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['pwd_attempts']),
1303
            'error' => $logError['error'],
1304
            'message' => $logError['message'],
1305
            'first_connection' => $_SESSION['validite_pw'] === false ? true : false,
1306
            'password_complexity' => TP_PW_COMPLEXITY[$_SESSION['user_pw_complexity']][1],
1307
        )
1308
    );
1309
1310
    $_SESSION['initial_url'] = '';
1311
    if ($SETTINGS['cpassman_dir'] === '..') {
1312
        $SETTINGS['cpassman_dir'] = '.';
1313
    }
1314
}
1315
1316
/**
1317
 * Undocumented function.
1318
 *
1319
 * @param string $username      Username
1320
 * @param string $ldap_suffix   Suffix
1321
 * @param string $passwordClear Password
1322
 * @param array  $SETTINGS      Teampass settings
1323
 *
1324
 * @return array
1325
 */
1326
function identifyViaLDAPPosixSearch($username, $ldap_suffix, $passwordClear, $SETTINGS)
0 ignored issues
show
Unused Code introduced by
The parameter $ldap_suffix is not used and could be removed. ( Ignorable by Annotation )

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

1326
function identifyViaLDAPPosixSearch($username, /** @scrutinizer ignore-unused */ $ldap_suffix, $passwordClear, $SETTINGS)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1327
{
1328
    // Load AntiXSS
1329
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
1330
    $antiXss = new protect\AntiXSS\AntiXSS();
1331
1332
    // load passwordLib library
1333
    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'].'/includes/libraries');
1334
    $pwdlib->register();
1335
    $pwdlib = new PasswordLib\PasswordLib();
1336
1337
    $ldapConnection = false;
1338
    $ldapURIs = '';
1339
    foreach (explode(',', $SETTINGS['ldap_domain_controler']) as $domainControler) {
1340
        if ($SETTINGS['ldap_ssl'] == 1) {
1341
            $ldapURIs .= 'ldaps://'.$domainControler.':'.$SETTINGS['ldap_port'].' ';
1342
        } else {
1343
            $ldapURIs .= 'ldap://'.$domainControler.':'.$SETTINGS['ldap_port'].' ';
1344
        }
1345
    }
1346
1347
    // Debug
1348
    debugIdentify(
1349
        $debugLdap,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $debugLdap seems to be never defined.
Loading history...
1350
        $dbgLdap,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dbgLdap seems to be never defined.
Loading history...
1351
        'LDAP URIs : '.$ldapURIs."\n"
1352
    );
1353
1354
    // Connect
1355
    $ldapconn = ldap_connect($ldapURIs);
1356
1357
    // Case of LDAP over TLS
1358
    if ($SETTINGS['ldap_tls']) {
1359
        ldap_start_tls($ldapconn);
1360
    }
1361
1362
    // Debug
1363
    debugIdentify(
1364
        $debugLdap,
1365
        $dbgLdap,
1366
        'LDAP connection : '.($ldapconn ? 'Connected' : 'Failed')."\n"
1 ignored issue
show
introduced by
$ldapconn is of type resource, thus it always evaluated to false.
Loading history...
1367
    );
1368
1369
    // Set options
1370
    ldap_set_option($ldapconn, LDAP_OPT_PROTOCOL_VERSION, 3);
1371
    ldap_set_option($ldapconn, LDAP_OPT_REFERRALS, 0);
1372
1373
    // Is LDAP connection ready?
1374
    if ($ldapconn !== false) {
1375
        // Should we bind the connection?
1376
        if ($SETTINGS['ldap_bind_dn'] !== '' && $SETTINGS['ldap_bind_passwd'] !== '') {
1377
            $ldapbind = ldap_bind($ldapconn, $SETTINGS['ldap_bind_dn'], $SETTINGS['ldap_bind_passwd']);
1378
1379
            // Debug
1380
            debugIdentify(
1381
                $debugLdap,
1382
                $dbgLdap,
1383
                'LDAP bind : '.($ldapbind ? 'Bound' : 'Failed')."\n"
1384
            );
1385
        } else {
1386
            $ldapbind = false;
1387
        }
1388
        if (($SETTINGS['ldap_bind_dn'] === '' && $SETTINGS['ldap_bind_passwd'] === '') || $ldapbind === true) {
1389
            $filter = '(&('.$SETTINGS['ldap_user_attribute'].'='.$username.')(objectClass='.$SETTINGS['ldap_object_class'].'))';
1390
            $result = ldap_search(
1391
                $ldapconn,
1392
                $SETTINGS['ldap_search_base'],
1393
                $filter,
1394
                array('dn', 'mail', 'givenname', 'sn', 'samaccountname', 'shadowexpire')
1395
            );
1396
1397
            // Debug
1398
            debugIdentify(
1399
                $debugLdap,
1400
                $dbgLdap,
1401
                'Search filter : '.$filter."\n".
1402
                    'Results : '.print_r(ldap_get_entries($ldapconn, $result), true)."\n"
1403
            );
1404
1405
            // Check if user was found in AD
1406
            if (ldap_count_entries($ldapconn, $result) > 0) {
1407
                // Get user's info and especially the DN
1408
                $result = ldap_get_entries($ldapconn, $result);
1409
                $user_dn = $result[0]['dn'];
1410
1411
                // Debug
1412
                debugIdentify(
1413
                    $debugLdap,
1414
                    $dbgLdap,
1415
                    'User was found. '.$user_dn.'\n'
1416
                );
1417
1418
                // Check shadowexpire attribute - if === 1 then user disabled
1419
                if (isset($result[0]['shadowexpire'][0]) === true && $result[0]['shadowexpire'][0] === '1') {
1420
                    return array(
1421
                        'error' => true,
1422
                        'message' => array(
1423
                            'value' => '',
1424
                            'user_admin' => isset($_SESSION['user_admin']) ? /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['user_admin']) : '',
1425
                            'initial_url' => @$_SESSION['initial_url'],
1426
                            'pwd_attempts' => /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['pwd_attempts']),
1427
                            'error' => 'user_not_exists',
1428
                            'message' => langHdl('error_bad_credentials'),
1429
                        ),
1430
                    );
1431
                }
1432
1433
                // Should we restrain the search in specified user groups
1434
                $GroupRestrictionEnabled = false;
1435
                if (isset($SETTINGS['ldap_usergroup']) === true && empty($SETTINGS['ldap_usergroup']) === false) {
1436
                    // New way to check User's group membership
1437
                    $filter_group = 'memberUid='.$username;
1438
                    $result_group = ldap_search(
1439
                        $ldapconn,
1440
                        $SETTINGS['ldap_search_base'],
1441
                        $filter_group,
1442
                        array('dn', 'samaccountname')
1443
                    );
1444
1445
                    if ($result_group) {
0 ignored issues
show
introduced by
$result_group is of type resource, thus it always evaluated to false.
Loading history...
1446
                        $entries = ldap_get_entries($ldapconn, $result_group);
1447
1448
                        // Debug
1449
                        debugIdentify(
1450
                            $debugLdap,
1451
                            $dbgLdap,
1452
                            'Search groups appartenance : '.$SETTINGS['ldap_search_base']."\n".
1453
                                'Results : '.print_r($entries, true)."\n"
1454
                        );
1455
1456
                        if ($entries['count'] > 0) {
1457
                            // Now check if group fits
1458
                            for ($i = 0; $i < $entries['count']; ++$i) {
1459
                                $parsr = ldap_explode_dn($entries[$i]['dn'], 0);
1460
                                if (str_replace(array('CN=', 'cn='), '', $parsr[0]) === $SETTINGS['ldap_usergroup']) {
1461
                                    $GroupRestrictionEnabled = true;
1462
                                    break;
1463
                                }
1464
                            }
1465
                        }
1466
                    }
1467
1468
                    // Debug
1469
                    debugIdentify(
1470
                        $debugLdap,
1471
                        $dbgLdap,
1472
                        'Group was found : '.var_export($GroupRestrictionEnabled, true)."\n"
1473
                    );
1474
                }
1475
1476
                // Is user in the LDAP?
1477
                if ($GroupRestrictionEnabled === true
1478
                    || ($GroupRestrictionEnabled === false
1479
                    && (isset($SETTINGS['ldap_usergroup']) === false
1480
                    || (isset($SETTINGS['ldap_usergroup']) === true
1481
                    && empty($SETTINGS['ldap_usergroup']) === true)))
1482
                ) {
1483
                    // Try to auth inside LDAP
1484
                    $ldapbind = ldap_bind($ldapconn, $user_dn, $passwordClear);
1485
                    if ($ldapbind === true) {
1486
                        $ldapConnection = true;
1487
1488
                        // Update user's password
1489
                        $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
1490
1491
                        // Do things if user exists in TP
1492
                        if ($counter > 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $counter seems to be never defined.
Loading history...
1493
                            // Update pwd in TP database
1494
                            DB::update(
1495
                                prefixTable('users'),
1496
                                array(
1497
                                    'pw' => $data['pw'],
1498
                                    'login' => $data['login'],
1499
                                ),
1500
                                'id = %i',
1501
                                $data['id']
1502
                            );
1503
1504
                            $proceedIdentification = true;
1505
                        }
1506
                    } else {
1507
                        $ldapConnection = false;
1508
                    }
1509
                }
1510
            } else {
1511
                $ldapConnection = false;
1512
            }
1513
        } else {
1514
            $ldapConnection = false;
1515
        }
1516
    } else {
1517
        $ldapConnection = false;
1518
    }
1519
1520
    return array(
1521
        'error' => false,
1522
        'message' => $ldapConnection,
1523
        'auth_username' => $username,
1524
        '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...
1525
        'proceedIdentification' => $proceedIdentification,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $proceedIdentification does not seem to be defined for all execution paths leading up to this point.
Loading history...
1526
    );
1527
}
1528
1529
/**
1530
 * Undocumented function.
1531
 *
1532
 * @param string $username      Username
1533
 * @param string $ldap_suffix   Suffix
1534
 * @param string $passwordClear Password
1535
 * @param array  $SETTINGS      Teampass settings
1536
 *
1537
 * @return array
1538
 */
1539
function identifyViaLDAPPosix($username, $ldap_suffix, $passwordClear, $SETTINGS)
0 ignored issues
show
Unused Code introduced by
The parameter $ldap_suffix is not used and could be removed. ( Ignorable by Annotation )

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

1539
function identifyViaLDAPPosix($username, /** @scrutinizer ignore-unused */ $ldap_suffix, $passwordClear, $SETTINGS)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1540
{
1541
    // Load AntiXSS
1542
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
1543
    $antiXss = new protect\AntiXSS\AntiXSS();
1544
1545
    // load passwordLib library
1546
    $pwdlib = new SplClassLoader('PasswordLib', $SETTINGS['cpassman_dir'].'/includes/libraries');
1547
    $pwdlib->register();
1548
    $pwdlib = new PasswordLib\PasswordLib();
1549
1550
    // Debug
1551
    debugIdentify(
1552
        $debugLdap,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $debugLdap seems to be never defined.
Loading history...
1553
        $dbgLdap,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $dbgLdap seems to be never defined.
Loading history...
1554
        "Get all ldap params : \n".
1555
        'base_dn : '.$SETTINGS['ldap_domain_dn']."\n".
1556
        'account_suffix : '.$SETTINGS['ldap_suffix']."\n".
1557
        'domain_controllers : '.$SETTINGS['ldap_domain_controler']."\n".
1558
        'ad_port : '.$SETTINGS['ldap_port']."\n".
1559
        'use_ssl : '.$SETTINGS['ldap_ssl']."\n".
1560
        'use_tls : '.$SETTINGS['ldap_tls']."\n*********\n\n"
1561
    );
1562
1563
    $adldap = new SplClassLoader('adLDAP', '../includes/libraries/LDAP');
1564
    $adldap->register();
1565
    $ldap_suffix = '';
1566
    $ldapConnection = false;
1567
1568
    // Posix style LDAP handles user searches a bit differently
1569
    if ($SETTINGS['ldap_type'] === 'posix') {
1570
        $ldap_suffix = ','.$SETTINGS['ldap_suffix'].','.$SETTINGS['ldap_domain_dn'];
1571
    } elseif ($SETTINGS['ldap_type'] === 'windows') {
1572
        //Multiple Domain Names
1573
        $ldap_suffix = $SETTINGS['ldap_suffix'];
1574
    }
1575
1576
    // Ensure no double commas exist in ldap_suffix
1577
    $ldap_suffix = str_replace(',,', ',', $ldap_suffix);
1578
1579
    // Create LDAP connection
1580
    $adldap = new adLDAP\adLDAP(
1581
        array(
1582
            'base_dn' => $SETTINGS['ldap_domain_dn'],
1583
            'account_suffix' => $ldap_suffix,
1584
            'domain_controllers' => explode(',', $SETTINGS['ldap_domain_controler']),
1585
            'ad_port' => $SETTINGS['ldap_port'],
1586
            'use_ssl' => $SETTINGS['ldap_ssl'],
1587
            'use_tls' => $SETTINGS['ldap_tls'],
1588
        )
1589
    );
1590
1591
    // Debug
1592
    debugIdentify(
1593
        $debugLdap,
1594
        $dbgLdap,
1595
        'Create new adldap object : '.$adldap->getLastError()."\n\n\n"
1596
    );
1597
1598
    // OpenLDAP expects an attribute=value pair
1599
    if ($SETTINGS['ldap_type'] === 'posix') {
1600
        $auth_username = $SETTINGS['ldap_user_attribute'].'='.$username;
1601
    } else {
1602
        $auth_username = $username;
1603
    }
1604
1605
    // Authenticate the user
1606
    if ($adldap->authenticate($auth_username, html_entity_decode($passwordClear))) {
1607
        // Is user in allowed group
1608
        if (isset($SETTINGS['ldap_allowed_usergroup']) === true
1609
            && empty($SETTINGS['ldap_allowed_usergroup']) === false
1610
        ) {
1611
            if ($adldap->user()->inGroup($auth_username, $SETTINGS['ldap_allowed_usergroup']) === true) {
1612
                $ldapConnection = true;
1613
            } else {
1614
                $ldapConnection = false;
1615
            }
1616
        } else {
1617
            $ldapConnection = true;
1618
        }
1619
1620
        // Is user expired?
1621
        if (is_array($adldap->user()->passwordExpiry($auth_username)) === false) {
0 ignored issues
show
introduced by
The condition is_array($adldap->user()...th_username)) === false is always false.
Loading history...
1622
            return array(
1623
                'error' => true,
1624
                'message' => array(
1625
                    'value' => '',
1626
                    'user_admin' => isset($_SESSION['user_admin']) ? /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['user_admin']) : '',
1627
                    'initial_url' => @$_SESSION['initial_url'],
1628
                    'pwd_attempts' => /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['pwd_attempts']),
1629
                    'error' => 'user_not_exists',
1630
                    'message' => langHdl('error_bad_credentials'),
1631
                ),
1632
            );
1633
        }
1634
1635
        // Update user's password
1636
        if ($ldapConnection === true) {
1637
            $data['pw'] = $pwdlib->createPasswordHash($passwordClear);
0 ignored issues
show
Comprehensibility Best Practice introduced by
$data was never initialized. Although not strictly required by PHP, it is generally a good practice to add $data = array(); before regardless.
Loading history...
1638
1639
            // Do things if user exists in TP
1640
            if ($counter > 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $counter seems to be never defined.
Loading history...
1641
                // Update pwd in TP database
1642
                DB::update(
1643
                    prefixTable('users'),
1644
                    array(
1645
                        'pw' => $data['pw'],
1646
                        'login' => $data['login'],
1647
                    ),
1648
                    'id = %i',
1649
                    $data['id']
1650
                );
1651
1652
                // No user creation is requested
1653
                $proceedIdentification = true;
1654
            }
1655
        }
1656
    } else {
1657
        $ldapConnection = false;
1658
    }
1659
1660
    // Debug
1661
    debugIdentify(
1662
        $debugLdap,
1663
        $dbgLdap,
1664
        'After authenticate : '.$adldap->getLastError()."\n\n\n".
1665
        'ldap status : '.$ldapConnection."\n\n\n"
1666
    );
1667
1668
    return array(
1669
        'error' => false,
1670
        'message' => $ldapConnection,
1671
        'auth_username' => $auth_username,
1672
        'proceedIdentification' => $proceedIdentification,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $proceedIdentification does not seem to be defined for all execution paths leading up to this point.
Loading history...
1673
        'user_info_from_ad' => $adldap->user()->info($auth_username, array('mail', 'givenname', 'sn')),
1674
    );
1675
}
1676
1677
/**
1678
 * Undocumented function.
1679
 *
1680
 * @param string $username     Username
1681
 * @param string $ldap_suffix  Suffix
1682
 * @param string $dataReceived Received data
1683
 * @param string $data         Result of query
1684
 * @param array  $SETTINGS     Teampass settings
1685
 *
1686
 * @return array
1687
 */
1688
function yubicoMFACheck($username, $ldap_suffix, $dataReceived, $data, $SETTINGS)
0 ignored issues
show
Unused Code introduced by
The parameter $username is not used and could be removed. ( Ignorable by Annotation )

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

1688
function yubicoMFACheck(/** @scrutinizer ignore-unused */ $username, $ldap_suffix, $dataReceived, $data, $SETTINGS)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
Unused Code introduced by
The parameter $ldap_suffix is not used and could be removed. ( Ignorable by Annotation )

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

1688
function yubicoMFACheck($username, /** @scrutinizer ignore-unused */ $ldap_suffix, $dataReceived, $data, $SETTINGS)

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
1689
{
1690
    // Load AntiXSS
1691
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/protect/AntiXSS/AntiXSS.php';
1692
    $antiXss = new protect\AntiXSS\AntiXSS();
1693
1694
    $yubico_key = htmlspecialchars_decode($dataReceived['yubico_key']);
1695
    $yubico_user_key = htmlspecialchars_decode($dataReceived['yubico_user_key']);
1696
    $yubico_user_id = htmlspecialchars_decode($dataReceived['yubico_user_id']);
1697
1698
    if (empty($yubico_user_key) === false && empty($yubico_user_id) === false) {
1699
        // save the new yubico in user's account
1700
        DB::update(
1701
            prefixTable('users'),
1702
            array(
1703
                'yubico_user_key' => $yubico_user_key,
1704
                'yubico_user_id' => $yubico_user_id,
1705
            ),
1706
            'id=%i',
1707
            $data['id']
1708
        );
1709
    } else {
1710
        // Check existing yubico credentials
1711
        if ($data['yubico_user_key'] === 'none' || $data['yubico_user_id'] === 'none') {
1712
            return array(
1713
                'error' => true,
1714
                'message' => array(
1715
                    'value' => '',
1716
                    'user_admin' => isset($_SESSION['user_admin']) ? /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['user_admin']) : '',
1717
                    'initial_url' => @$_SESSION['initial_url'],
1718
                    'pwd_attempts' => /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['pwd_attempts']),
1719
                    'error' => 'no_user_yubico_credentials',
1720
                    'message' => '',
1721
                ),
1722
            );
1723
        } else {
1724
            $yubico_user_key = $data['yubico_user_key'];
1725
            $yubico_user_id = $data['yubico_user_id'];
1726
        }
1727
    }
1728
1729
    // Now check yubico validity
1730
    include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/Yubico/Yubico.php';
1731
    $yubi = new Auth_Yubico($yubico_user_id, $yubico_user_key);
1732
    $auth = $yubi->verify($yubico_key);
1733
1734
    if (PEAR::isError($auth)) {
1735
        $proceedIdentification = false;
0 ignored issues
show
Unused Code introduced by
The assignment to $proceedIdentification is dead and can be removed.
Loading history...
1736
1737
        return array(
1738
            'error' => true,
1739
            'message' => array(
1740
                'value' => '',
1741
                'user_admin' => isset($_SESSION['user_admin']) ? /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['user_admin']) : '',
1742
                'initial_url' => @$_SESSION['initial_url'],
1743
                'pwd_attempts' => /* @scrutinizer ignore-type */ $antiXss->xss_clean($_SESSION['pwd_attempts']),
1744
                'error' => 'bad_user_yubico_credentials',
1745
                'message' => langHdl('yubico_bad_code'),
1746
            ),
1747
        );
1748
    } else {
1749
        $proceedIdentification = true;
1750
    }
1751
1752
    return array(
1753
        'error' => false,
1754
        'message' => '',
1755
        'proceedIdentification' => $proceedIdentification,
1756
    );
1757
}
1758
1759
/**
1760
 * Undocumented function.
1761
 *
1762
 * @param string $username          Username
1763
 * @param string $data              Result of query
1764
 * @param string $user_info_from_ad Received data
1765
 * @param array  $SETTINGS          Teampass settings
1766
 *
1767
 * @return array
1768
 */
1769
function ldapCreateUser($username, $data, $user_info_from_ad, $SETTINGS)
1770
{
1771
    DB::insert(
1772
        prefixTable('users'),
1773
        array(
1774
            'login' => $username,
1775
            'pw' => $data['pw'],
1776
            'email' => (isset($user_info_from_ad[0]['mail'][0]) === false) ? '' : $user_info_from_ad[0]['mail'][0],
1777
            'name' => $user_info_from_ad[0]['givenname'][0],
1778
            'lastname' => $user_info_from_ad[0]['sn'][0],
1779
            'admin' => '0',
1780
            'gestionnaire' => '0',
1781
            'can_manage_all_users' => '0',
1782
            'personal_folder' => $SETTINGS['enable_pf_feature'] === '1' ? '1' : '0',
1783
            'fonction_id' => isset($SETTINGS['ldap_new_user_role']) === true ? $SETTINGS['ldap_new_user_role'] : '0',
1784
            'groupes_interdits' => '',
1785
            'groupes_visibles' => '',
1786
            'last_pw_change' => time(),
1787
            'user_language' => $SETTINGS['default_language'],
1788
            'encrypted_psk' => '',
1789
            '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,
1790
        )
1791
    );
1792
    $newUserId = DB::insertId();
1793
    // Create personnal folder
1794
    if (isset($SETTINGS['enable_pf_feature']) === true && $SETTINGS['enable_pf_feature'] === '1') {
1795
        DB::insert(
1796
            prefixTable('nested_tree'),
1797
            array(
1798
                'parent_id' => '0',
1799
                'title' => $newUserId,
1800
                'bloquer_creation' => '0',
1801
                'bloquer_modification' => '0',
1802
                'personal_folder' => '1',
1803
            )
1804
        );
1805
1806
        // Rebuild tree
1807
        $tree = new SplClassLoader('Tree\NestedTree', $SETTINGS['cpassman_dir'].'/includes/libraries');
1808
        $tree->register();
1809
        $tree = new Tree\NestedTree\NestedTree(prefixTable('nested_tree'), 'id', 'parent_id', 'title');
1810
        $tree->rebuild();
1811
    }
1812
1813
    return array(
1814
        'error' => false,
1815
        'message' => '',
1816
        'proceedIdentification' => $proceedIdentification,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $proceedIdentification seems to be never defined.
Loading history...
1817
        'user_initial_creation_through_ldap' => true,
1818
    );
1819
}
1820
1821
/**
1822
 * Undocumented function.
1823
 *
1824
 * @param string $data         Result of query
1825
 * @param string $dataReceived DataReceived
1826
 * @param array  $SETTINGS     Teampass settings
1827
 *
1828
 * @return array
1829
 */
1830
function GoogleMFACheck($data, $dataReceived, $SETTINGS)
1831
{
1832
    if (isset($dataReceived['GACode']) && empty($dataReceived['GACode']) === false) {
1833
        $firstTime = array();
1834
1835
        // load library
1836
        include_once $SETTINGS['cpassman_dir'].'/includes/libraries/Authentication/TwoFactorAuth/TwoFactorAuth.php';
1837
1838
        // create new instance
1839
        $tfa = new Authentication\TwoFactorAuth\TwoFactorAuth($SETTINGS['ga_website_name']);
1840
1841
        // now check if it is the 1st time the user is using 2FA
1842
        if ($data['ga_temporary_code'] !== 'none' && $data['ga_temporary_code'] !== 'done') {
1843
            if ($data['ga_temporary_code'] !== $dataReceived['GACode']) {
1844
                return array(
1845
                    'error' => true,
1846
                    'message' => langHdl('ga_bad_code'),
1847
                    'proceedIdentification' => false,
1848
                );
1849
            } else {
1850
                $proceedIdentification = false;
1851
                $logError = array(
1852
                    'error' => 'ga_temporary_code_correct',
1853
                    'message' => langHdl('ga_flash_qr_and_login'),
1854
                );
1855
1856
                // generate new QR
1857
                $new_2fa_qr = $tfa->getQRCodeImageAsDataUri(
1858
                    'Teampass - '.$username,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $username seems to be never defined.
Loading history...
1859
                    $data['ga']
1860
                );
1861
1862
                // clear temporary code from DB
1863
                DB::update(
1864
                    prefixTable('users'),
1865
                    array(
1866
                        'ga_temporary_code' => 'done',
1867
                    ),
1868
                    'id=%i',
1869
                    $data['id']
1870
                );
1871
            }
1872
1873
            $firstTime = array(
1874
                'value' => '<img src="'.$new_2fa_qr.'">',
1875
                'user_admin' => isset($_SESSION['user_admin']) ? (int) $_SESSION['user_admin'] : 0,
1876
                'initial_url' => @$_SESSION['initial_url'],
1877
                'pwd_attempts' => (int) $_SESSION['pwd_attempts'],
1878
                'error' => $logError['error'],
1879
                'message' => $logError['message'],
1880
            );
1881
        } else {
1882
            // verify the user GA code
1883
            if ($tfa->verifyCode($data['ga'], $dataReceived['GACode'])) {
1884
                $proceedIdentification = true;
1885
            } else {
1886
                return array(
1887
                    'error' => true,
1888
                    'message' => langHdl('ga_bad_code'),
1889
                    'proceedIdentification' => false,
1890
                );
1891
            }
1892
        }
1893
    } else {
1894
        return array(
1895
            'error' => true,
1896
            'message' => langHdl('ga_bad_code'),
1897
            'proceedIdentification' => false,
1898
        );
1899
    }
1900
1901
    return array(
1902
        'error' => false,
1903
        'message' => '',
1904
        'proceedIdentification' => $proceedIdentification,
1905
        'firstTime' => $firstTime,
1906
    );
1907
}
1908
1909
/**
1910
 * Undocumented function.
1911
 *
1912
 * @param string $enabled text1
1913
 * @param string $dbgFile text2
1914
 * @param string $text    text3
1915
 */
1916
function debugIdentify($enabled, $dbgFile, $text)
1917
{
1918
    if ($enabled === 1) {
0 ignored issues
show
introduced by
The condition $enabled === 1 is always false.
Loading history...
1919
        fputs(
1920
            $dbgFile,
1921
            $text
1922
        );
1923
    }
1924
}
1925