* Copyright 2014 MyBB Group, All Rights Reserved
* Website: http://www.mybb.com
* License: http://www.mybb.com/about/license
// Here you can change how much of an Admin CP IP address must match in a previous session for the user is validated (e.g. 3 means a.b.c need to match)
define("ADMIN_IP_SEGMENTS", 0);
define("ADMIN_IPV6_SEGMENTS", 0);
require_once dirname(dirname(__FILE__))."/inc/init.php";
$shutdown_queries = $shutdown_functions = array();
header('X-Frame-Options: SAMEORIGIN');
header('Referrer-Policy: no-referrer');
if(!isset($config['admin_dir']) || !file_exists(MYBB_ROOT.$config['admin_dir']."/inc/class_page.php"))
$config['admin_dir'] = basename(dirname(__FILE__));
define('MYBB_ADMIN_DIR', MYBB_ROOT.$config['admin_dir'].'/');
define('COPY_YEAR', my_date('Y', TIME_NOW));
require_once MYBB_ADMIN_DIR."inc/class_page.php";
require_once MYBB_ADMIN_DIR."inc/class_form.php";
require_once MYBB_ADMIN_DIR."inc/class_table.php";
require_once MYBB_ADMIN_DIR."inc/functions.php";
require_once MYBB_ROOT."inc/functions_user.php";
// Set cookie path to our admin dir temporarily, i.e. so that it affects the ACP only
$loc = get_current_location('', '', true);
$mybb->settings['cookiepath'] = substr($loc, 0, strrpos($loc, "/{$config['admin_dir']}/"))."/{$config['admin_dir']}/";
$lang->set_language($mybb->settings['cplanguage'], "admin");
// Load global language phrases
$lang->load("messages", true);
if(function_exists('mb_internal_encoding') && !empty($lang->settings['charset']))
@mb_internal_encoding($lang->settings['charset']);
header("Content-type: text/html; charset={$lang->settings['charset']}");
if(is_dir(MYBB_ROOT."install") && !file_exists(MYBB_ROOT."install/lock"))
$mybb->trigger_generic_error("install_directory");
if(!empty($mybb->settings['cpstyle']) && file_exists(MYBB_ADMIN_DIR."/styles/".$mybb->settings['cpstyle']."/main.css"))
$cp_style = $mybb->settings['cpstyle'];
$default_page = new DefaultPage;
foreach(array('action', 'do', 'module') as $input)
if(!isset($mybb->input[$input]))
$mybb->input[$input] = '';
if($mybb->input['action'] == "unlock")
$plugins->run_hooks("admin_unlock_start");
if($mybb->input['username'])
$user = get_user_by_username($mybb->input['username'], array('fields' => '*'));
$error = $lang->error_invalid_username;
else if($mybb->input['uid'])
$user = get_user($mybb->input['uid']);
$error = $lang->error_invalid_uid;
// Do we have the token? If so let's process it
if($mybb->input['token'] && $user['uid'])
$query = $db->simple_select("awaitingactivation", "COUNT(aid) AS num", "uid='".(int)$user['uid']."' AND code='".$db->escape_string($mybb->input['token'])."' AND type='l'");
$plugins->run_hooks("admin_unlock_end");
if($db->fetch_field($query, "num") > 0)
$db->delete_query("awaitingactivation", "uid='".(int)$user['uid']."' AND code='".$db->escape_string($mybb->input['token'])."' AND type='l'");
$db->update_query("adminoptions", array('loginlockoutexpiry' => 0, 'loginattempts' => 0), "uid='".(int)$user['uid']."'");
admin_redirect("index.php");
$error = $lang->error_invalid_token;
$default_page->show_lockout_unlock($error, 'error');
elseif($mybb->input['do'] == "login")
$plugins->run_hooks("admin_login");
// We have an adminsid cookie?
if(isset($mybb->cookies['adminsid']))
$query = $db->simple_select("adminsessions", "sid", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
$admin_session = $db->fetch_field($query, 'sid');
// Session found: redirect to index
admin_redirect("index.php");
require_once MYBB_ROOT."inc/datahandlers/login.php";
$loginhandler = new LoginDataHandler("get");
// Determine login method
$login_lang_string = $lang->error_invalid_username_password;
switch($mybb->settings['username_method'])
$login_lang_string = $lang->sprintf($login_lang_string, $lang->login_username);
$login_lang_string = $lang->sprintf($login_lang_string, $lang->login_email);
case 2: // Username and email
$login_lang_string = $lang->sprintf($login_lang_string, $lang->login_username_and_password);
if(!empty($config['secret_pin']) && (empty($mybb->input['pin']) || $mybb->input['pin'] != $config['secret_pin']))
$login_user = get_user_by_username($mybb->input['username'], array('fields' => array('email', 'username')));
$plugins->run_hooks("admin_login_incorrect_pin");
if($login_user['uid'] > 0)
$db->update_query("adminoptions", array("loginattempts" => "loginattempts+1"), "uid='".(int)$login_user['uid']."'", '', true);
$loginattempts = login_attempt_check_acp($login_user['uid'], true);
// Have we attempted too many times?
if($loginattempts !== false && $loginattempts['loginattempts'] > 0)
// Have we set an expiry yet?
if($loginattempts['loginlockoutexpiry'] == 0)
$db->update_query("adminoptions", array("loginlockoutexpiry" => TIME_NOW+((int)$mybb->settings['loginattemptstimeout']*60)), "uid='".(int)$login_user['uid']."'");
// Did we hit lockout for the first time? Send the unlock email to the administrator
if($loginattempts['loginattempts'] == $mybb->settings['maxloginattempts'])
$db->delete_query("awaitingactivation", "uid='".(int)$login_user['uid']."' AND type='l'");
"uid" => $login_user['uid'],
$db->insert_query("awaitingactivation", $lockout_array);
$subject = $lang->sprintf($lang->locked_out_subject, $mybb->settings['bbname']);
$message = $lang->sprintf($lang->locked_out_message, htmlspecialchars_uni($mybb->input['username']), $mybb->settings['bbname'], $mybb->settings['maxloginattempts'], $mybb->settings['bburl'], $mybb->config['admin_dir'], $lockout_array['code'], $lockout_array['uid']);
my_mail($login_user['email'], $subject, $message);
'type' => 'admin_locked_out',
'uid' => (int)$login_user['uid'],
'username' => $login_user['username'],
$default_page->show_lockedout();
$default_page->show_login($login_lang_string, "error");
$loginhandler->set_data(array(
'username' => $mybb->input['username'],
'password' => $mybb->input['password']
if($loginhandler->validate_login() == true)
$mybb->user = get_user($loginhandler->login_data['uid']);
if(!empty($mybb->user['uid']))
if(login_attempt_check_acp($mybb->user['uid']) == true)
'type' => 'admin_locked_out',
'uid' => (int)$mybb->user['uid'],
'username' => $mybb->user['username'],
$default_page->show_lockedout();
$plugins->run_hooks("admin_login_success");
$db->delete_query("adminsessions", "uid='{$mybb->user['uid']}'");
$sid = md5(random_str(50));
$useragent = $_SERVER['HTTP_USER_AGENT'];
if(my_strlen($useragent) > 200)
$useragent = my_substr($useragent, 0, 200);
// Create a new admin session for this user
"uid" => $mybb->user['uid'],
"loginkey" => $mybb->user['loginkey'],
"ip" => $db->escape_binary(my_inet_pton(get_ip())),
"lastactive" => TIME_NOW,
"data" => my_serialize(array()),
"useragent" => $db->escape_string($useragent),
$db->insert_query("adminsessions", $admin_session);
$admin_session['data'] = array();
// Only reset the loginattempts when we're really logged in and the user doesn't need to enter a 2fa code
$query = $db->simple_select("adminoptions", "authsecret", "uid='{$mybb->user['uid']}'");
$admin_options = $db->fetch_array($query);
if(empty($admin_options['authsecret']))
$db->update_query("adminoptions", array("loginattempts" => 0, "loginlockoutexpiry" => 0), "uid='{$mybb->user['uid']}'");
my_setcookie("adminsid", $sid, '', true, "strict");
my_setcookie('acploginattempts', 0);
$mybb->request_method = "get";
if(!empty($mybb->input['module']))
// $query_string should contain the module
$query_string = '?module='.htmlspecialchars_uni($mybb->input['module']);
// Now we look for any paramters passed in $_SERVER['QUERY_STRING']
if($_SERVER['QUERY_STRING'])
$qstring = '?'.preg_replace('#adminsid=(.{32})#i', '', $_SERVER['QUERY_STRING']);
$qstring = str_replace('action=logout', '', $qstring);
$qstring = preg_replace('#&+#', '&', $qstring);
$qstring = str_replace('?&', '?', $qstring);
// So what do we do? We know that parameters are devided by ampersands
// That means we must get to work!
$parameters = explode('&', $qstring);
// Remove our first member if it's for the module
if(substr($parameters[0], 0, 8) == '?module=')
foreach($parameters as $key => $param)
$params = explode("=", $param);
$query_string .= '&'.htmlspecialchars_uni($params[0]);
$query_string .= "=".htmlspecialchars_uni($params[1]);
admin_redirect("index.php".$query_string);
$login_user = get_user_by_username($mybb->input['username'], array('fields' => array('email', 'username')));
$plugins->run_hooks("admin_login_fail");
if(!empty($login_user['uid']) && $login_user['uid'] > 0)
$db->update_query("adminoptions", array("loginattempts" => "loginattempts+1"), "uid='".(int)$login_user['uid']."'", '', true);
$loginattempts = login_attempt_check_acp($login_user['uid'], true);
// Have we attempted too many times?
if($loginattempts !== false && $loginattempts['loginattempts'] > 0)
// Have we set an expiry yet?
if($loginattempts['loginlockoutexpiry'] == 0)
$db->update_query("adminoptions", array("loginlockoutexpiry" => TIME_NOW+((int)$mybb->settings['loginattemptstimeout']*60)), "uid='".(int)$login_user['uid']."'");
$plugins->run_hooks("admin_login_lockout");
// Did we hit lockout for the first time? Send the unlock email to the administrator
if($loginattempts['loginattempts'] == $mybb->settings['maxloginattempts'])
$db->delete_query("awaitingactivation", "uid='".(int)$login_user['uid']."' AND type='l'");
"uid" => $login_user['uid'],
$db->insert_query("awaitingactivation", $lockout_array);
$subject = $lang->sprintf($lang->locked_out_subject, $mybb->settings['bbname']);
$message = $lang->sprintf($lang->locked_out_message, htmlspecialchars_uni($mybb->input['username']), $mybb->settings['bbname'], $mybb->settings['maxloginattempts'], $mybb->settings['bburl'], $mybb->config['admin_dir'], $lockout_array['code'], $lockout_array['uid']);
my_mail($login_user['email'], $subject, $message);
'type' => 'admin_locked_out',
'uid' => (int)$login_user['uid'],
'username' => $login_user['username'],
$default_page->show_lockedout();
// No admin session - show message on the login screen
if(!isset($mybb->cookies['adminsid']))
// Otherwise, check admin session
$query = $db->simple_select("adminsessions", "*", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
$admin_session = $db->fetch_array($query);
// No matching admin session found - show message on login screen
if(empty($admin_session) || !$admin_session['sid'])
$login_message = $lang->error_invalid_admin_session;
$admin_session['data'] = my_unserialize($admin_session['data']);
// Fetch the user from the admin session
$mybb->user = get_user($admin_session['uid']);
// Login key has changed - force logout
if(!$mybb->user['uid'] || $mybb->user['loginkey'] !== $admin_session['loginkey'])
// Admin CP sessions 2 hours old are expired
if($admin_session['lastactive'] < TIME_NOW-7200)
$login_message = $lang->error_admin_session_expired;
$db->delete_query("adminsessions", "sid='".$db->escape_string($mybb->cookies['adminsid'])."'");
// If IP matching is set - check IP address against the session IP
else if(ADMIN_IP_SEGMENTS > 0 && strpos($ip_address, ':') === false)
$exploded_ip = explode(".", $ip_address);
$exploded_admin_ip = explode(".", my_inet_ntop($admin_session['ip']));
for($i = 0; $i < ADMIN_IP_SEGMENTS; ++$i)
if($exploded_ip[$i] == $exploded_admin_ip[$i])
if($matches == ADMIN_IP_SEGMENTS)
// IP doesn't match properly - show message on logon screen
$login_message = $lang->error_invalid_ip;
else if(ADMIN_IPV6_SEGMENTS > 0 && strpos($ip_address, ':') !== false)
$hex = unpack("H*hex", my_inet_pton($ip_address));
$expanded_ip = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex['hex']), 0, -1);
$hex_admin = unpack("H*hex", $admin_session['ip']);
$expanded_admin_ip = substr(preg_replace("/([A-f0-9]{4})/", "$1:", $hex_admin['hex']), 0, -1);
$exploded_ip = explode(":", $expanded_ip);
$exploded_admin_ip = explode(":", $expanded_admin_ip);
for($i = 0; $i < ADMIN_IPV6_SEGMENTS; ++$i)
if($exploded_ip[$i] == $exploded_admin_ip[$i])
if($matches == ADMIN_IPV6_SEGMENTS)
// IP doesn't match properly - show message on logon screen
$login_message = $lang->error_invalid_ip;