checkCode($user['tfa_secret'], $token)) { $_SESSION[SESS_USER_2FA] = time(); // About using the user agent: It's easy to fake it, but it increases the barrier for stealing and reusing cookies nevertheless // and it doesn't do any harm (except that it's invalid after a browser upgrade, but that may be even intended) $cookie = $_SESSION[SESS_USER_2FA] . ':' . hash_hmac('sha1', $user['username'] . ':' . $tfaMins . ':' . $_SESSION[SESS_USER_2FA] . ':' . $_SERVER['HTTP_USER_AGENT'], $user['tfa_secret']); $cookie_lifetime = read_config_option('secpass_2fatime') * 60; cacti_cookie_set(session_name() . '_otp', $cookie, time() + ($cookie_lifetime)); } else { $_SESSION[SESS_USER_2FA] = false; } } } else { $_SESSION[SESS_USER_2FA] = time(); } // Process the user if ($_SESSION[SESS_USER_2FA]) { if (isset($user['tfa_enabled'])) { cacti_log("LOGIN: User '" . $user['username'] . "' 2FA Authenticated", false, 'AUTH'); $client_addr = get_client_addr(); db_execute_prepared('INSERT IGNORE INTO user_log (username, user_id, result, ip, time) VALUES (?, ?, 2, ?, NOW())', [$user['username'], $user['id'], $client_addr]); } } else { // BAD token cacti_log("DEBUG: User '" . $user['username'] . "' failed to verify 2fa token", false, 'AUTH', POLLER_VERBOSITY_DEBUG); // Structured failure line for fail2ban, at normal verbosity (the human line // above is DEBUG-only). A failed second factor is a brute-force signal too. auth_log_failure($user['username'], auth_realm_token((int) ($user['realm'] ?? 0)), '2fa'); db_execute_prepared('INSERT IGNORE INTO user_log (username, user_id, result, ip, time) VALUES (?, 0, 3, ?, NOW())', [$user['username'], get_client_addr()]); $message = __('Failed to verify token'); } } if (empty($user['tfa_enabled'])) { $_SESSION[SESS_USER_2FA] = true; } if (!empty($_SESSION[SESS_USER_2FA])) { auth_login_redirect($user['login_opts']); exit; } if (api_plugin_hook_function('custom_2fa_login', OPER_MODE_NATIVE) == OPER_MODE_RESKIN) { return; } $selectedTheme = get_selected_theme(); html_auth_header('login_2fa', __('2nd Factor Authentication'), __('2FA Verification'), __('Enter your token'), [ 'username' => $user['username'], 'action' => gnrv('action') ] ); ?> '>     $(function() { $('#login_token').focus(); }); ");