209 lines
7.3 KiB
PHP
209 lines
7.3 KiB
PHP
<?php
|
|
$connection = '';
|
|
|
|
$has_token = $_SESSION["token"];
|
|
if (!$has_token) {
|
|
$_SESSION["token"] = rand(1, 1e6); // 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*60, 0); // active for 30 minutes
|
|
}
|
|
$invalid[1]++;
|
|
file_write_unlock($fp, serialize($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 // 1 - auth
|
|
|| DRIVER != $vendor
|
|
|| SERVER != $server
|
|
|| $_GET["username"] !== $username // "0" == "00"
|
|
|| DB != $db
|
|
) {
|
|
redirect(auth_url($vendor, $server, $username, $db));
|
|
}
|
|
|
|
} elseif ($_POST["logout"]) {
|
|
if ($has_token && !verify_token()) {
|
|
page_header(lang('Logout'), lang('Invalid CSRF token. Send the form again.'));
|
|
page_footer("db");
|
|
exit;
|
|
} else {
|
|
foreach (array("pwds", "db", "dbs", "queries") as $key) {
|
|
set_session($key, null);
|
|
}
|
|
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, $username, decrypt_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 .= '<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(DRIVER, SERVER, $_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'), $error, null);
|
|
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(":", SERVER, 2);
|
|
if (is_numeric($port) && ($port < 1024 || $port > 65535)) {
|
|
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 ($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.');
|
|
}
|
|
}
|