<?php
$connection 
'';

$has_token $_SESSION["token"];
if (!
$has_token) {
    
$_SESSION["token"] = rand(11e6); // defense against cross-site request forgery
}
$token get_token(); ///< @var string CSRF protection

$permanent = array();
if (
$_COOKIE["adminer_permanent"]) {
    foreach (
explode(" "$_COOKIE["adminer_permanent"]) as $val) {
        list(
$key) = explode(":"$val);
        
$permanent[$key] = $val;
    }
}

function 
add_invalid_login() {
    global 
$adminer;
    
$fp file_open_lock(get_temp_dir() . "/adminer.invalid");
    if (!
$fp) {
        return;
    }
    
$invalids unserialize(stream_get_contents($fp));
    
$time time();
    if (
$invalids) {
        foreach (
$invalids as $ip => $val) {
            if (
$val[0] < $time) {
                unset(
$invalids[$ip]);
            }
        }
    }
    
$invalid = &$invalids[$adminer->bruteForceKey()];
    if (!
$invalid) {
        
$invalid = array($time 30*600); // active for 30 minutes
    
}
    
$invalid[1]++;
    
file_write_unlock($fpserialize($invalids));
}

function 
check_invalid_login() {
    global 
$adminer;
    
$invalids unserialize(@file_get_contents(get_temp_dir() . "/adminer.invalid")); // @ - may not exist
    
$invalid $invalids[$adminer->bruteForceKey()];
    
$next_attempt = ($invalid[1] > 29 $invalid[0] - time() : 0); // allow 30 invalid attempts
    
if ($next_attempt 0) { //! do the same with permanent login
        
auth_error(lang('Too many unsuccessful logins, try again in %d minute(s).'ceil($next_attempt 60)));
    }
}

$auth $_POST["auth"];
if (
$auth) {
    
session_regenerate_id(); // defense against session fixation
    
$vendor $auth["driver"];
    
$server $auth["server"];
    
$username $auth["username"];
    
$password = (string) $auth["password"];
    
$db $auth["db"];
    
set_password($vendor$server$username$password);
    
$_SESSION["db"][$vendor][$server][$username][$db] = true;
    if (
$auth["permanent"]) {
        
$key base64_encode($vendor) . "-" base64_encode($server) . "-" base64_encode($username) . "-" base64_encode($db);
        
$private $adminer->permanentLogin(true);
        
$permanent[$key] = "$key:" base64_encode($private encrypt_string($password$private) : "");
        
cookie("adminer_permanent"implode(" "$permanent));
    }
    if (
count($_POST) == // 1 - auth
        
|| DRIVER != $vendor
        
|| SERVER != $server
        
|| $_GET["username"] !== $username // "0" == "00"
        
|| DB != $db
    
) {
        
redirect(auth_url($vendor$server$username$db));
    }
    
} elseif (
$_POST["logout"] && (!$has_token || verify_token())) {
    foreach (array(
"pwds""db""dbs""queries") as $key) {
        
set_session($keynull);
    }
    
unset_permanent();
    
redirect(substr(preg_replace('~\b(username|db|ns)=[^&]*&~'''ME), 0, -1), lang('Logout successful.') . ' ' lang('Thanks for using Adminer, consider <a href="https://www.adminer.org/en/donation/">donating</a>.'));
    
} elseif (
$permanent && !$_SESSION["pwds"]) {
    
session_regenerate_id();
    
$private $adminer->permanentLogin();
    foreach (
$permanent as $key => $val) {
        list(, 
$cipher) = explode(":"$val);
        list(
$vendor$server$username$db) = array_map('base64_decode'explode("-"$key));
        
set_password($vendor$server$usernamedecrypt_string(base64_decode($cipher), $private));
        
$_SESSION["db"][$vendor][$server][$username][$db] = true;
    }
}

function 
unset_permanent() {
    global 
$permanent;
    foreach (
$permanent as $key => $val) {
        list(
$vendor$server$username$db) = array_map('base64_decode'explode("-"$key));
        if (
$vendor == DRIVER && $server == SERVER && $username == $_GET["username"] && $db == DB) {
            unset(
$permanent[$key]);
        }
    }
    
cookie("adminer_permanent"implode(" "$permanent));
}

/** Renders an error message and a login form
* @param string plain text
* @return null exits
*/
function auth_error($error) {
    global 
$adminer$has_token;
    
$session_name session_name();
    if (isset(
$_GET["username"])) {
        
header("HTTP/1.1 403 Forbidden"); // 401 requires sending WWW-Authenticate header
        
if (($_COOKIE[$session_name] || $_GET[$session_name]) && !$has_token) {
            
$error lang('Session expired, please login again.');
        } else {
            
restart_session();
            
add_invalid_login();
            
$password get_password();
            if (
$password !== null) {
                if (
$password === false) {
                    
$error .= ($error '<br>' '') . lang('Master password expired. <a href="https://www.adminer.org/en/extension/"%s>Implement</a> %s method to make it permanent.'target_blank(), '<code>permanentLogin()</code>');
                }
                
set_password(DRIVERSERVER$_GET["username"], null);
            }
            
unset_permanent();
        }
    }
    if (!
$_COOKIE[$session_name] && $_GET[$session_name] && ini_bool("session.use_only_cookies")) {
        
$error lang('Session support must be enabled.');
    }
    
$params session_get_cookie_params();
    
cookie("adminer_key", ($_COOKIE["adminer_key"] ? $_COOKIE["adminer_key"] : rand_string()), $params["lifetime"]);
    
page_header(lang('Login'), $errornull);
    echo 
"<form action='' method='post'>\n";
    echo 
"<div>";
    if (
hidden_fields($_POST, array("auth"))) { // expired session
        
echo "<p class='message'>" lang('The action will be performed after successful login with the same credentials.') . "\n";
    }
    echo 
"</div>\n";
    
$adminer->loginForm();
    echo 
"</form>\n";
    
page_footer("auth");
    exit;
}

if (isset(
$_GET["username"]) && !class_exists("Min_DB")) {
    unset(
$_SESSION["pwds"][DRIVER]);
    
unset_permanent();
    
page_header(lang('No extension'), lang('None of the supported PHP extensions (%s) are available.'implode(", "$possible_drivers)), false);
    
page_footer("auth");
    exit;
}

stop_session(true);

if (isset(
$_GET["username"]) && is_string(get_password())) {
    list(
$host$port) = explode(":"SERVER2);
    if (
preg_match('~^\s*([-+]?\d+)~'$port$match) && ($match[1] < 1024 || $match[1] > 65535)) { // is_numeric('80#') would still connect to port 80
        
auth_error(lang('Connecting to privileged ports is not allowed.'));
    }
    
check_invalid_login();
    
$connection connect();
    
$driver = new Min_Driver($connection);
}

$login null;
if (!
is_object($connection) || ($login $adminer->login($_GET["username"], get_password())) !== true) {
    
$error = (is_string($connection) ? h($connection) : (is_string($login) ? $login lang('Invalid credentials.')));
    
auth_error($error . (preg_match('~^ | $~'get_password()) ? '<br>' lang('There is a space in the input password which might be the cause.') : ''));
}

if (
$_POST["logout"] && $has_token && !verify_token()) {
    
page_header(lang('Logout'), lang('Invalid CSRF token. Send the form again.'));
    
page_footer("db");
    exit;
}

if (
$auth && $_POST["token"]) {
    
$_POST["token"] = $token// reset token after explicit login
}

$error ''///< @var string
if ($_POST) {
    if (!
verify_token()) {
        
$ini "max_input_vars";
        
$max_vars ini_get($ini);
        if (
extension_loaded("suhosin")) {
            foreach (array(
"suhosin.request.max_vars""suhosin.post.max_vars") as $key) {
                
$val ini_get($key);
                if (
$val && (!$max_vars || $val $max_vars)) {
                    
$ini $key;
                    
$max_vars $val;
                }
            }
        }
        
$error = (!$_POST["token"] && $max_vars
            
lang('Maximum number of allowed fields exceeded. Please increase %s.'"'$ini'")
            : 
lang('Invalid CSRF token. Send the form again.') . ' ' lang('If you did not send this request from Adminer then close this page.')
        );
    }
    
} elseif (
$_SERVER["REQUEST_METHOD"] == "POST") {
    
// posted form with no data means that post_max_size exceeded because Adminer always sends token at least
    
$error lang('Too big POST data. Reduce the data or increase the %s configuration directive.'"'post_max_size'");
    if (isset(
$_GET["sql"])) {
        
$error .= ' ' lang('You can upload a big SQL file via FTP and import it from server.');
    }
}