SHARE
TWEET

LogInOut.php

a guest Dec 10th, 2011 208 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <?php
  2.  
  3. /**
  4.  * Simple Machines Forum (SMF)
  5.  *
  6.  * @package SMF
  7.  * @author Simple Machines http://www.simplemachines.org
  8.  * @copyright 2011 Simple Machines
  9.  * @license http://www.simplemachines.org/about/smf/license.php BSD
  10.  *
  11.  * @version 2.0
  12.  */
  13.  
  14. if (!defined('SMF'))
  15.         die('Hacking attempt...');
  16.  
  17. /*      This file is concerned pretty entirely, as you see from its name, with
  18.         logging in and out members, and the validation of that.  It contains:
  19.  
  20.         void Login()
  21.                 - shows a page for the user to type in their username and password.
  22.                 - caches the referring URL in $_SESSION['login_url'].
  23.                 - uses the Login template and language file with the login sub
  24.                   template.
  25.                 - if you are using a wireless device, uses the protocol_login sub
  26.                   template in the Wireless template.
  27.                 - accessed from ?action=login.
  28.  
  29.         void Login2()
  30.                 - actually logs you in and checks that login was successful.
  31.                 - employs protection against a specific IP or user trying to brute
  32.                   force a login to an account.
  33.                 - on error, uses the same templates Login() uses.
  34.                 - upgrades password encryption on login, if necessary.
  35.                 - after successful login, redirects you to $_SESSION['login_url'].
  36.                 - accessed from ?action=login2, by forms.
  37.  
  38.         void Logout(bool internal = false)
  39.                 - logs the current user out of their account.
  40.                 - requires that the session hash is sent as well, to prevent automatic
  41.                   logouts by images or javascript.
  42.                 - doesn't check the session if internal is true.
  43.                 - redirects back to $_SESSION['logout_url'], if it exists.
  44.                 - accessed via ?action=logout;session_var=...
  45.  
  46.         string md5_hmac(string data, string key)
  47.                 - old style SMF 1.0.x/YaBB SE 1.5.x hashing.
  48.                 - returns the HMAC MD5 of data with key.
  49.  
  50.         string phpBB3_password_check(string passwd, string passwd_hash)
  51.                 - custom encryption for phpBB3 based passwords.
  52.  
  53.         void validatePasswordFlood(id_member, password_flood_value = false, was_correct = false)
  54.                 - this function helps protect against brute force attacks on a member's password.
  55. */
  56.  
  57. // Ask them for their login information.
  58. function Login()
  59. {
  60.         global $txt, $context, $scripturl;
  61.  
  62.         // In wireless?  If so, use the correct sub template.
  63.         if (WIRELESS)
  64.                 $context['sub_template'] = WIRELESS_PROTOCOL . '_login';
  65.         // Otherwise, we need to load the Login template/language file.
  66.         else
  67.         {
  68.                 loadLanguage('Login');
  69.                 loadTemplate('Login');
  70.                 $context['sub_template'] = 'login';
  71.         }
  72.  
  73.         // Get the template ready.... not really much else to do.
  74.         $context['page_title'] = $txt['login'];
  75.         $context['default_username'] = &$_REQUEST['u'];
  76.         $context['default_password'] = '';
  77.         $context['never_expire'] = false;
  78.  
  79.         // Add the login chain to the link tree.
  80.         $context['linktree'][] = array(
  81.                 'url' => $scripturl . '?action=login',
  82.                 'name' => $txt['login'],
  83.         );
  84.  
  85.         // Set the login URL - will be used when the login process is done (but careful not to send us to an attachment).
  86.         if (isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0)
  87.                 $_SESSION['login_url'] = $_SESSION['old_url'];
  88.         else
  89.                 unset($_SESSION['login_url']);
  90. }
  91.  
  92. // Perform the actual logging-in.
  93. function Login2()
  94. {
  95.         global $txt, $scripturl, $user_info, $user_settings, $smcFunc;
  96.         global $cookiename, $maintenance, $modSettings, $context, $sc, $sourcedir;
  97.  
  98.         // Load cookie authentication stuff.
  99.         require_once($sourcedir . '/Subs-Auth.php');
  100.  
  101.         if (isset($_GET['sa']) && $_GET['sa'] == 'salt' && !$user_info['is_guest'])
  102.         {
  103.                 if (isset($_COOKIE[$cookiename]) && preg_match('~^a:[34]:\{i:0;(i:\d{1,6}|s:[1-8]:"\d{1,8}");i:1;s:(0|40):"([a-fA-F0-9]{40})?";i:2;[id]:\d{1,14};(i:3;i:\d;)?\}$~', $_COOKIE[$cookiename]) === 1)
  104.                         list (, , $timeout) = @unserialize($_COOKIE[$cookiename]);
  105.                 elseif (isset($_SESSION['login_' . $cookiename]))
  106.                         list (, , $timeout) = @unserialize($_SESSION['login_' . $cookiename]);
  107.                 else
  108.                         trigger_error('Login2(): Cannot be logged in without a session or cookie', E_USER_ERROR);
  109.  
  110.                 $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
  111.                 updateMemberData($user_info['id'], array('password_salt' => $user_settings['password_salt']));
  112.  
  113.                 setLoginCookie($timeout - time(), $user_info['id'], sha1($user_settings['passwd'] . $user_settings['password_salt']));
  114.  
  115.                 redirectexit('action=login2;sa=check;member=' . $user_info['id'], $context['server']['needs_login_fix']);
  116.         }
  117.         // Double check the cookie...
  118.         elseif (isset($_GET['sa']) && $_GET['sa'] == 'check')
  119.         {
  120.                 // Strike!  You're outta there!
  121.                 if ($_GET['member'] != $user_info['id'])
  122.                         fatal_lang_error('login_cookie_error', false);
  123.  
  124.                 // Some whitelisting for login_url...
  125.                 if (empty($_SESSION['login_url']))
  126.                         redirectexit();
  127.                 else
  128.                 {
  129.                         // Best not to clutter the session data too much...
  130.                         $temp = $_SESSION['login_url'];
  131.                         unset($_SESSION['login_url']);
  132.  
  133.                         redirectexit($temp);
  134.                 }
  135.         }
  136.  
  137.         // Beyond this point you are assumed to be a guest trying to login.
  138.         if (!$user_info['is_guest'])
  139.                 redirectexit();
  140.  
  141.         // Are you guessing with a script?
  142.         spamProtection('login');
  143.  
  144.         // Set the login_url if it's not already set (but careful not to send us to an attachment).
  145.         if (empty($_SESSION['login_url']) && isset($_SESSION['old_url']) && strpos($_SESSION['old_url'], 'dlattach') === false && preg_match('~(board|topic)[=,]~', $_SESSION['old_url']) != 0)
  146.                 $_SESSION['login_url'] = $_SESSION['old_url'];
  147.  
  148.         // Been guessing a lot, haven't we?
  149.         if (isset($_SESSION['failed_login']) && $_SESSION['failed_login'] >= $modSettings['failed_login_threshold'] * 3)
  150.                 fatal_lang_error('login_threshold_fail', 'critical');
  151.  
  152.         // Set up the cookie length.  (if it's invalid, just fall through and use the default.)
  153.         if (isset($_POST['cookieneverexp']) || (!empty($_POST['cookielength']) && $_POST['cookielength'] == -1))
  154.                 $modSettings['cookieTime'] = 3153600;
  155.         elseif (!empty($_POST['cookielength']) && ($_POST['cookielength'] >= 1 || $_POST['cookielength'] <= 525600))
  156.                 $modSettings['cookieTime'] = (int) $_POST['cookielength'];
  157.  
  158.         loadLanguage('Login');
  159.         // Load the template stuff - wireless or normal.
  160.         if (WIRELESS)
  161.                 $context['sub_template'] = WIRELESS_PROTOCOL . '_login';
  162.         else
  163.         {
  164.                 loadTemplate('Login');
  165.                 $context['sub_template'] = 'login';
  166.         }
  167.  
  168.         // Set up the default/fallback stuff.
  169.         $context['default_username'] = isset($_POST['user']) ? preg_replace('~&amp;#(\\d{1,7}|x[0-9a-fA-F]{1,6});~', '&#\\1;', htmlspecialchars($_POST['user'])) : '';
  170.         $context['default_password'] = '';
  171.         $context['never_expire'] = $modSettings['cookieTime'] == 525600 || $modSettings['cookieTime'] == 3153600;
  172.         $context['login_errors'] = array($txt['error_occured']);
  173.         $context['page_title'] = $txt['login'];
  174.  
  175.         // Add the login chain to the link tree.
  176.         $context['linktree'][] = array(
  177.                 'url' => $scripturl . '?action=login',
  178.                 'name' => $txt['login'],
  179.         );
  180.  
  181.         if (!empty($_POST['openid_identifier']) && !empty($modSettings['enableOpenID']))
  182.         {
  183.                 require_once($sourcedir . '/Subs-OpenID.php');
  184.                 if (($open_id = smf_openID_validate($_POST['openid_identifier'])) !== 'no_data')
  185.                         return $open_id;
  186.         }
  187.  
  188.         // You forgot to type your username, dummy!
  189.         if (!isset($_POST['user']) || $_POST['user'] == '')
  190.         {
  191.                 $context['login_errors'] = array($txt['need_username']);
  192.                 return;
  193.         }
  194.  
  195.         // Hmm... maybe 'admin' will login with no password. Uhh... NO!
  196.         if ((!isset($_POST['passwrd']) || $_POST['passwrd'] == '') && (!isset($_POST['hash_passwrd']) || strlen($_POST['hash_passwrd']) != 40))
  197.         {
  198.                 $context['login_errors'] = array($txt['no_password']);
  199.                 return;
  200.         }
  201.  
  202.         // No funky symbols either.
  203.         if (preg_match('~[<>&"\'=\\\]~', preg_replace('~(&#(\\d{1,7}|x[0-9a-fA-F]{1,6});)~', '', $_POST['user'])) != 0)
  204.         {
  205.                 $context['login_errors'] = array($txt['error_invalid_characters_username']);
  206.                 return;
  207.         }
  208.  
  209.         // Are we using any sort of integration to validate the login?
  210.         if (in_array('retry', call_integration_hook('integrate_validate_login', array($_POST['user'], isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40 ? $_POST['hash_passwrd'] : null, $modSettings['cookieTime'])), true))
  211.         {
  212.                 $context['login_errors'] = array($txt['login_hash_error']);
  213.                 $context['disable_login_hashing'] = true;
  214.                 return;
  215.         }
  216.  
  217.         // Load the data up!
  218.         $request = $smcFunc['db_query']('', '
  219.                 SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt,
  220.                         openid_uri, passwd_flood
  221.                 FROM {db_prefix}members
  222.                 WHERE ' . ($smcFunc['db_case_sensitive'] ? 'LOWER(member_name) = LOWER({string:user_name})' : 'member_name = {string:user_name}') . '
  223.                 LIMIT 1',
  224.                 array(
  225.                         'user_name' => $smcFunc['db_case_sensitive'] ? strtolower($_POST['user']) : $_POST['user'],
  226.                 )
  227.         );
  228.         // Probably mistyped or their email, try it as an email address. (member_name first, though!)
  229.         if ($smcFunc['db_num_rows']($request) == 0)
  230.         {
  231.                 $smcFunc['db_free_result']($request);
  232.  
  233.                 $request = $smcFunc['db_query']('', '
  234.                         SELECT passwd, id_member, id_group, lngfile, is_activated, email_address, additional_groups, member_name, password_salt, openid_uri,
  235.                         passwd_flood
  236.                         FROM {db_prefix}members
  237.                         WHERE email_address = {string:user_name}
  238.                         LIMIT 1',
  239.                         array(
  240.                                 'user_name' => $_POST['user'],
  241.                         )
  242.                 );
  243.                 // Let them try again, it didn't match anything...
  244.                 if ($smcFunc['db_num_rows']($request) == 0)
  245.                 {
  246.                         $context['login_errors'] = array($txt['username_no_exist']);
  247.                         return;
  248.                 }
  249.         }
  250.  
  251.         $user_settings = $smcFunc['db_fetch_assoc']($request);
  252.         $smcFunc['db_free_result']($request);
  253.  
  254.         // Figure out the password using SMF's encryption - if what they typed is right.
  255.         if (isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40)
  256.         {
  257.                 // Needs upgrading?
  258.                 if (strlen($user_settings['passwd']) != 40)
  259.                 {
  260.                         $context['login_errors'] = array($txt['login_hash_error']);
  261.                         $context['disable_login_hashing'] = true;
  262.                         unset($user_settings);
  263.                         return;
  264.                 }
  265.                 // Challenge passed.
  266.                 elseif ($_POST['hash_passwrd'] == sha1($user_settings['passwd'] . $sc))
  267.                         $sha_passwd = $user_settings['passwd'];
  268.                 else
  269.                 {
  270.                         // Don't allow this!
  271.                         validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
  272.  
  273.                         $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1;
  274.  
  275.                         if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold'])
  276.                                 redirectexit('action=reminder');
  277.                         else
  278.                         {
  279.                                 log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user');
  280.  
  281.                                 $context['disable_login_hashing'] = true;
  282.                                 $context['login_errors'] = array($txt['incorrect_password']);
  283.                                 unset($user_settings);
  284.                                 return;
  285.                         }
  286.                 }
  287.         }
  288.         else
  289.                 $sha_passwd = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd']));
  290.  
  291.         // Bad password!  Thought you could fool the database?!
  292.         if ($user_settings['passwd'] != $sha_passwd)
  293.         {
  294.                 // Let's be cautious, no hacking please. thanx.
  295.                 validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood']);
  296.  
  297.                 // Maybe we were too hasty... let's try some other authentication methods.
  298.                 $other_passwords = array();
  299.  
  300.                 // None of the below cases will be used most of the time (because the salt is normally set.)
  301.                 if ($user_settings['password_salt'] == '')
  302.                 {
  303.                         // YaBB SE, Discus, MD5 (used a lot), SHA-1 (used some), SMF 1.0.x, IkonBoard, and none at all.
  304.                         $other_passwords[] = crypt($_POST['passwrd'], substr($_POST['passwrd'], 0, 2));
  305.                         $other_passwords[] = crypt($_POST['passwrd'], substr($user_settings['passwd'], 0, 2));
  306.                         $other_passwords[] = md5($_POST['passwrd']);
  307.                         $other_passwords[] = sha1($_POST['passwrd']);
  308.                         $other_passwords[] = md5_hmac($_POST['passwrd'], strtolower($user_settings['member_name']));
  309.                         $other_passwords[] = md5($_POST['passwrd'] . strtolower($user_settings['member_name']));
  310.                         $other_passwords[] = md5(md5($_POST['passwrd']));
  311.                         $other_passwords[] = $_POST['passwrd'];
  312.  
  313.                         // This one is a strange one... MyPHP, crypt() on the MD5 hash.
  314.                         $other_passwords[] = crypt(md5($_POST['passwrd']), md5($_POST['passwrd']));
  315.  
  316.                         // Snitz style - SHA-256.  Technically, this is a downgrade, but most PHP configurations don't support sha256 anyway.
  317.                         if (strlen($user_settings['passwd']) == 64 && function_exists('mhash') && defined('MHASH_SHA256'))
  318.                                 $other_passwords[] = bin2hex(mhash(MHASH_SHA256, $_POST['passwrd']));
  319.  
  320.                         // phpBB3 users new hashing.  We now support it as well ;).
  321.                         $other_passwords[] = phpBB3_password_check($_POST['passwrd'], $user_settings['passwd']);
  322.  
  323.                         // APBoard 2 Login Method.
  324.                         $other_passwords[] = md5(crypt($_POST['passwrd'], 'CRYPT_MD5'));
  325.                 }
  326.                 // The hash should be 40 if it's SHA-1, so we're safe with more here too.
  327.                 elseif (strlen($user_settings['passwd']) == 32)
  328.                 {
  329.                         // vBulletin 3 style hashing?  Let's welcome them with open arms \o/.
  330.                         $other_passwords[] = md5(md5($_POST['passwrd']) . $user_settings['password_salt']);
  331.  
  332.                         // Hmm.. p'raps it's Invision 2 style?
  333.                         $other_passwords[] = md5(md5($user_settings['password_salt']) . md5($_POST['passwrd']));
  334.  
  335.                         // Some common md5 ones.
  336.                         $other_passwords[] = md5($user_settings['password_salt'] . $_POST['passwrd']);
  337.                         $other_passwords[] = md5($_POST['passwrd'] . $user_settings['password_salt']);
  338.                 }
  339.                 elseif (strlen($user_settings['passwd']) == 40)
  340.                 {
  341.                         // Maybe they are using a hash from before the password fix.
  342.                         $other_passwords[] = sha1(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd']));
  343.  
  344.                         // BurningBoard3 style of hashing.
  345.                         $other_passwords[] = sha1($user_settings['password_salt'] . sha1($user_settings['password_salt'] . sha1($_POST['passwrd'])));
  346.  
  347.                         // Perhaps we converted to UTF-8 and have a valid password being hashed differently.
  348.                         if ($context['character_set'] == 'utf8' && !empty($modSettings['previousCharacterSet']) && $modSettings['previousCharacterSet'] != 'utf8')
  349.                         {
  350.                                 // Try iconv first, for no particular reason.
  351.                                 if (function_exists('iconv'))
  352.                                         $other_passwords['iconv'] = sha1(strtolower(iconv('UTF-8', $modSettings['previousCharacterSet'], $user_settings['member_name'])) . un_htmlspecialchars(iconv('UTF-8', $modSettings['previousCharacterSet'], $_POST['passwrd'])));
  353.  
  354.                                 // Say it aint so, iconv failed!
  355.                                 if (empty($other_passwords['iconv']) && function_exists('mb_convert_encoding'))
  356.                                         $other_passwords[] = sha1(strtolower(mb_convert_encoding($user_settings['member_name'], 'UTF-8', $modSettings['previousCharacterSet'])) . un_htmlspecialchars(mb_convert_encoding($_POST['passwrd'], 'UTF-8', $modSettings['previousCharacterSet'])));
  357.                         }
  358.                 }
  359.  
  360.                 // SMF's sha1 function can give a funny result on Linux (Not our fault!). If we've now got the real one let the old one be valid!
  361.                 if (strpos(strtolower(PHP_OS), 'win') !== 0)
  362.                 {
  363.                         require_once($sourcedir . '/Subs-Compat.php');
  364.                         $other_passwords[] = sha1_smf(strtolower($user_settings['member_name']) . un_htmlspecialchars($_POST['passwrd']));
  365.                 }
  366.  
  367.                 // Whichever encryption it was using, let's make it use SMF's now ;).
  368.                 if (in_array($user_settings['passwd'], $other_passwords))
  369.                 {
  370.                         $user_settings['passwd'] = $sha_passwd;
  371.                         $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
  372.  
  373.                         // Update the password and set up the hash.
  374.                         updateMemberData($user_settings['id_member'], array('passwd' => $user_settings['passwd'], 'password_salt' => $user_settings['password_salt'], 'passwd_flood' => ''));
  375.                 }
  376.                 // Okay, they for sure didn't enter the password!
  377.                 else
  378.                 {
  379.                         // They've messed up again - keep a count to see if they need a hand.
  380.                         $_SESSION['failed_login'] = @$_SESSION['failed_login'] + 1;
  381.  
  382.                         // Hmm... don't remember it, do you?  Here, try the password reminder ;).
  383.                         if ($_SESSION['failed_login'] >= $modSettings['failed_login_threshold'])
  384.                                 redirectexit('action=reminder');
  385.                         // We'll give you another chance...
  386.                         else
  387.                         {
  388.                                 // Log an error so we know that it didn't go well in the error log.
  389.                                 log_error($txt['incorrect_password'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', 'user');
  390.  
  391.                                 $context['login_errors'] = array($txt['incorrect_password']);
  392.                                 return;
  393.                         }
  394.                 }
  395.         }
  396.         elseif (!empty($user_settings['passwd_flood']))
  397.         {
  398.                 // Let's be sure they weren't a little hacker.
  399.                 validatePasswordFlood($user_settings['id_member'], $user_settings['passwd_flood'], true);
  400.  
  401.                 // If we got here then we can reset the flood counter.
  402.                 updateMemberData($user_settings['id_member'], array('passwd_flood' => ''));
  403.         }
  404.  
  405.         // Correct password, but they've got no salt; fix it!
  406.         if ($user_settings['password_salt'] == '')
  407.         {
  408.                 $user_settings['password_salt'] = substr(md5(mt_rand()), 0, 4);
  409.                 updateMemberData($user_settings['id_member'], array('password_salt' => $user_settings['password_salt']));
  410.         }
  411.  
  412.         // Check their activation status.
  413.         if (!checkActivation())
  414.                 return;
  415.  
  416.         DoLogin();
  417. }
  418.  
  419. function checkActivation()
  420. {
  421.         global $context, $txt, $scripturl, $user_settings, $modSettings;
  422.  
  423.         if (!isset($context['login_errors']))
  424.                 $context['login_errors'] = array();
  425.  
  426.         // What is the true activation status of this account?
  427.         $activation_status = $user_settings['is_activated'] > 10 ? $user_settings['is_activated'] - 10 : $user_settings['is_activated'];
  428.  
  429.         // Check if the account is activated - COPPA first...
  430.         if ($activation_status == 5)
  431.         {
  432.                 $context['login_errors'][] = $txt['coppa_no_concent'] . ' <a href="' . $scripturl . '?action=coppa;member=' . $user_settings['id_member'] . '">' . $txt['coppa_need_more_details'] . '</a>';
  433.                 return false;
  434.         }
  435.         // Awaiting approval still?
  436.         elseif ($activation_status == 3)
  437.                 fatal_lang_error('still_awaiting_approval', 'user');
  438.         // Awaiting deletion, changed their mind?
  439.         elseif ($activation_status == 4)
  440.         {
  441.                 if (isset($_REQUEST['undelete']))
  442.                 {
  443.                         updateMemberData($user_settings['id_member'], array('is_activated' => 1));
  444.                         updateSettings(array('unapprovedMembers' => ($modSettings['unapprovedMembers'] > 0 ? $modSettings['unapprovedMembers'] - 1 : 0)));
  445.                 }
  446.                 else
  447.                 {
  448.                         $context['disable_login_hashing'] = true;
  449.                         $context['login_errors'][] = $txt['awaiting_delete_account'];
  450.                         $context['login_show_undelete'] = true;
  451.                         return false;
  452.                 }
  453.         }
  454.         // Standard activation?
  455.         elseif ($activation_status != 1)
  456.         {
  457.                 log_error($txt['activate_not_completed1'] . ' - <span class="remove">' . $user_settings['member_name'] . '</span>', false);
  458.  
  459.                 $context['login_errors'][] = $txt['activate_not_completed1'] . ' <a href="' . $scripturl . '?action=activate;sa=resend;u=' . $user_settings['id_member'] . '">' . $txt['activate_not_completed2'] . '</a>';
  460.                 return false;
  461.         }
  462.         return true;
  463. }
  464.  
  465. function DoLogin()
  466. {
  467.         global $txt, $scripturl, $user_info, $user_settings, $smcFunc;
  468.         global $cookiename, $maintenance, $modSettings, $context, $sourcedir;
  469.  
  470.         // Load cookie authentication stuff.
  471.         require_once($sourcedir . '/Subs-Auth.php');
  472.  
  473.         // Call login integration functions.
  474.         call_integration_hook('integrate_login', array($user_settings['member_name'], isset($_POST['hash_passwrd']) && strlen($_POST['hash_passwrd']) == 40 ? $_POST['hash_passwrd'] : null, $modSettings['cookieTime']));
  475.  
  476.         // Get ready to set the cookie...
  477.         $username = $user_settings['member_name'];
  478.         $user_info['id'] = $user_settings['id_member'];
  479.  
  480.         // Bam!  Cookie set.  A session too, just in case.
  481.         setLoginCookie(60 * $modSettings['cookieTime'], $user_settings['id_member'], sha1($user_settings['passwd'] . $user_settings['password_salt']));
  482.  
  483.         // Reset the login threshold.
  484.         if (isset($_SESSION['failed_login']))
  485.                 unset($_SESSION['failed_login']);
  486.  
  487.         $user_info['is_guest'] = false;
  488.         $user_settings['additional_groups'] = explode(',', $user_settings['additional_groups']);
  489.         $user_info['is_admin'] = $user_settings['id_group'] == 1 || in_array(1, $user_settings['additional_groups']);
  490.  
  491.         // Are you banned?
  492.         is_not_banned(true);
  493.  
  494.         // An administrator, set up the login so they don't have to type it again.
  495.         if ($user_info['is_admin'] && isset($user_settings['openid_uri']) && empty($user_settings['openid_uri']))
  496.         {
  497.                 $_SESSION['admin_time'] = time();
  498.                 unset($_SESSION['just_registered']);
  499.         }
  500.  
  501.         // Don't stick the language or theme after this point.
  502.         unset($_SESSION['language'], $_SESSION['id_theme']);
  503.  
  504.         // First login?
  505.         $request = $smcFunc['db_query']('', '
  506.                 SELECT last_login
  507.                 FROM {db_prefix}members
  508.                 WHERE id_member = {int:id_member}
  509.                         AND last_login = 0',
  510.                 array(
  511.                         'id_member' => $user_info['id'],
  512.                 )
  513.         );
  514.         if ($smcFunc['db_num_rows']($request) == 1)
  515.                 $_SESSION['first_login'] = true;
  516.         else
  517.                 unset($_SESSION['first_login']);
  518.         $smcFunc['db_free_result']($request);
  519.  
  520.         // You've logged in, haven't you?
  521.         updateMemberData($user_info['id'], array('last_login' => time(), 'member_ip' => $user_info['ip'], 'member_ip2' => $_SERVER['BAN_CHECK_IP']));
  522.  
  523.         // Get rid of the online entry for that old guest....
  524.         $smcFunc['db_query']('', '
  525.                 DELETE FROM {db_prefix}log_online
  526.                 WHERE session = {string:session}',
  527.                 array(
  528.                         'session' => 'ip' . $user_info['ip'],
  529.                 )
  530.         );
  531.         $_SESSION['log_time'] = 0;
  532.  
  533.         // Just log you back out if it's in maintenance mode and you AREN'T an admin.
  534.         if (empty($maintenance) || allowedTo('admin_forum'))
  535.                 redirectexit('action=login2;sa=check;member=' . $user_info['id'], $context['server']['needs_login_fix']);
  536.         else
  537.                 redirectexit('action=logout;' . $context['session_var'] . '=' . $context['session_id'], $context['server']['needs_login_fix']);
  538. }
  539.  
  540. // Log the user out.
  541. function Logout($internal = false, $redirect = true)
  542. {
  543.         global $sourcedir, $user_info, $user_settings, $context, $modSettings, $smcFunc;
  544.  
  545.         // Make sure they aren't being auto-logged out.
  546.         if (!$internal)
  547.                 checkSession('get');
  548.  
  549.         require_once($sourcedir . '/Subs-Auth.php');
  550.  
  551.         if (isset($_SESSION['pack_ftp']))
  552.                 $_SESSION['pack_ftp'] = null;
  553.  
  554.         // They cannot be open ID verified any longer.
  555.         if (isset($_SESSION['openid']))
  556.                 unset($_SESSION['openid']);
  557.  
  558.         // It won't be first login anymore.
  559.         unset($_SESSION['first_login']);
  560.  
  561.         // Just ensure they aren't a guest!
  562.         if (!$user_info['is_guest'])
  563.         {
  564.                 // Pass the logout information to integrations.
  565.                 call_integration_hook('integrate_logout', array($user_settings['member_name']));
  566.  
  567.                 // If you log out, you aren't online anymore :P.
  568.                 $smcFunc['db_query']('', '
  569.                         DELETE FROM {db_prefix}log_online
  570.                         WHERE id_member = {int:current_member}',
  571.                         array(
  572.                                 'current_member' => $user_info['id'],
  573.                         )
  574.                 );
  575.         }
  576.  
  577.         $_SESSION['log_time'] = 0;
  578.  
  579.         // Empty the cookie! (set it in the past, and for id_member = 0)
  580.         setLoginCookie(-3600, 0);
  581.  
  582.         // Off to the merry board index we go!
  583.         if ($redirect)
  584.         {
  585.                 if (empty($_SESSION['logout_url']))
  586.                         redirectexit('', $context['server']['needs_login_fix']);
  587.                 else
  588.                 {
  589.                         $temp = $_SESSION['logout_url'];
  590.                         unset($_SESSION['logout_url']);
  591.  
  592.                         redirectexit($temp, $context['server']['needs_login_fix']);
  593.                 }
  594.         }
  595. }
  596.  
  597. // MD5 Encryption used for older passwords.
  598. function md5_hmac($data, $key)
  599. {
  600.         $key = str_pad(strlen($key) <= 64 ? $key : pack('H*', md5($key)), 64, chr(0x00));
  601.         return md5(($key ^ str_repeat(chr(0x5c), 64)) . pack('H*', md5(($key ^ str_repeat(chr(0x36), 64)) . $data)));
  602. }
  603.  
  604. // Special encryption used by phpBB3.
  605. function phpBB3_password_check($passwd, $passwd_hash)
  606. {
  607.         // Too long or too short?
  608.         if (strlen($passwd_hash) != 34)
  609.                 return;
  610.  
  611.         // Range of characters allowed.
  612.         $range = './0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
  613.  
  614.         // Tests
  615.         $strpos = strpos($range, $passwd_hash[3]);
  616.         $count = 1 << $strpos;
  617.         $count2 = $count;
  618.         $salt = substr($passwd_hash, 4, 8);
  619.  
  620.         // Things are done differently for PHP 5.
  621.         if (@version_compare(PHP_VERSION, '5') >= 0)
  622.         {
  623.                 $hash = md5($salt . $passwd, true);
  624.                 for (; $count != 0; --$count)
  625.                         $hash = md5($hash . $passwd, true);
  626.         }
  627.         else
  628.         {
  629.                 $hash = pack('H*', md5($salt . $passwd));
  630.                 for (; $count != 0; --$count)
  631.                         $hash = pack('H*', md5($hash . $passwd));
  632.         }
  633.  
  634.         $output = substr($passwd_hash, 0, 12);
  635.         $i = 0;
  636.         while ($i < 16)
  637.         {
  638.                 $value = ord($hash[$i++]);
  639.                 $output .= $range[$value & 0x3f];
  640.  
  641.                 if ($i < 16)
  642.                         $value |= ord($hash[$i]) << 8;
  643.  
  644.                 $output .= $range[($value >> 6) & 0x3f];
  645.  
  646.                 if ($i++ >= 16)
  647.                         break;
  648.  
  649.                 if ($i < 16)
  650.                         $value |= ord($hash[$i]) << 16;
  651.  
  652.                 $output .= $range[($value >> 12) & 0x3f];
  653.  
  654.                 if ($i++ >= 16)
  655.                         break;
  656.  
  657.                 $output .= $range[($value >> 18) & 0x3f];
  658.         }
  659.  
  660.         // Return now.
  661.         return $output;
  662. }
  663.  
  664. // This protects against brute force attacks on a member's password. Importantly even if the password was right we DON'T TELL THEM!
  665. function validatePasswordFlood($id_member, $password_flood_value = false, $was_correct = false)
  666. {
  667.         global $smcFunc, $cookiename, $sourcedir;
  668.  
  669.         // As this is only brute protection, we allow 5 attempts every 10 seconds.
  670.  
  671.         // Destroy any session or cookie data about this member, as they validated wrong.
  672.         require_once($sourcedir . '/Subs-Auth.php');
  673.         setLoginCookie(-3600, 0);
  674.  
  675.         if (isset($_SESSION['login_' . $cookiename]))
  676.                 unset($_SESSION['login_' . $cookiename]);
  677.  
  678.         // We need a member!
  679.         if (!$id_member)
  680.         {
  681.                 // Redirect back!
  682.                 redirectexit();
  683.  
  684.                 // Probably not needed, but still make sure...
  685.                 fatal_lang_error('no_access', false);
  686.         }
  687.  
  688.         // Right, have we got a flood value?
  689.         if ($password_flood_value !== false)
  690.                 @list ($time_stamp, $number_tries) = explode('|', $password_flood_value);
  691.  
  692.         // Timestamp invalid or non-existent?
  693.         if (empty($number_tries) || $time_stamp < (time() - 10))
  694.         {
  695.                 // If it wasn't *that* long ago, don't give them another five goes.
  696.                 $number_tries = !empty($number_tries) && $time_stamp < (time() - 20) ? 2 : 0;
  697.                 $time_stamp = time();
  698.         }
  699.  
  700.         $number_tries++;
  701.  
  702.         // Broken the law?
  703.         if ($number_tries > 5)
  704.                 fatal_lang_error('login_threshold_brute_fail', 'critical');
  705.  
  706.         // Otherwise set the members data. If they correct on their first attempt then we actually clear it, otherwise we set it!
  707.         updateMemberData($id_member, array('passwd_flood' => $was_correct && $number_tries == 1 ? '' : $time_stamp . '|' . $number_tries));
  708.  
  709. }
  710.  
  711. ?>
  712.  
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
Not a member of Pastebin yet?
Sign Up, it unlocks many cool features!
 
Top