1<?php 2/** 3 * Handles logins, logouts, and password reset requests. 4 * 5 * @copyright (C) 2008-2012 PunBB, partially based on code (C) 2008-2009 FluxBB.org 6 * @license http://www.gnu.org/licenses/gpl.html GPL version 2 or higher 7 * @package PunBB 8 */ 9 10 11if (isset($_GET['action'])) 12 define('FORUM_QUIET_VISIT', 1); 13 14if (!defined('FORUM_ROOT')) 15 define('FORUM_ROOT', './'); 16require FORUM_ROOT.'include/common.php'; 17 18($hook = get_hook('li_start')) ? eval($hook) : null; 19 20// Load the login.php language file 21require FORUM_ROOT.'lang/'.$forum_user['language'].'/login.php'; 22 23 24$action = isset($_GET['action']) ? $_GET['action'] : null; 25$errors = array(); 26 27// Login 28if (isset($_POST['form_sent']) && empty($action)) 29{ 30 $form_username = forum_trim($_POST['req_username']); 31 $form_password = forum_trim($_POST['req_password']); 32 $save_pass = isset($_POST['save_pass']); 33 34 ($hook = get_hook('li_login_form_submitted')) ? eval($hook) : null; 35 36 // Get user info matching login attempt 37 $query = array( 38 'SELECT' => 'u.id, u.group_id, u.password, u.salt', 39 'FROM' => 'users AS u' 40 ); 41 42 if (in_array($db_type, array('mysql', 'mysqli', 'mysql_innodb', 'mysqli_innodb'))) 43 $query['WHERE'] = 'username=\''.$forum_db->escape($form_username).'\''; 44 else 45 $query['WHERE'] = 'LOWER(username)=LOWER(\''.$forum_db->escape($form_username).'\')'; 46 47 ($hook = get_hook('li_login_qr_get_login_data')) ? eval($hook) : null; 48 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 49 list($user_id, $group_id, $db_password_hash, $salt) = $forum_db->fetch_row($result); 50 51 $authorized = false; 52 if (!empty($db_password_hash)) 53 { 54 $sha1_in_db = (strlen($db_password_hash) == 40) ? true : false; 55 $form_password_hash = forum_hash($form_password, $salt); 56 57 if ($sha1_in_db && $db_password_hash == $form_password_hash) 58 $authorized = true; 59 else if ((!$sha1_in_db && $db_password_hash == md5($form_password)) || ($sha1_in_db && $db_password_hash == sha1($form_password))) 60 { 61 $authorized = true; 62 63 $salt = random_key(12); 64 $form_password_hash = forum_hash($form_password, $salt); 65 66 // There's an old MD5 hash or an unsalted SHA1 hash in the database, so we replace it 67 // with a randomly generated salt and a new, salted SHA1 hash 68 $query = array( 69 'UPDATE' => 'users', 70 'SET' => 'password=\''.$form_password_hash.'\', salt=\''.$forum_db->escape($salt).'\'', 71 'WHERE' => 'id='.$user_id 72 ); 73 74 ($hook = get_hook('li_login_qr_update_user_hash')) ? eval($hook) : null; 75 $forum_db->query_build($query) or error(__FILE__, __LINE__); 76 } 77 } 78 79 ($hook = get_hook('li_login_pre_auth_message')) ? eval($hook) : null; 80 81 if (!$authorized) 82 $errors[] = sprintf($lang_login['Wrong user/pass']); 83 84 // Did everything go according to plan? 85 if (empty($errors)) 86 { 87 // Update the status if this is the first time the user logged in 88 if ($group_id == FORUM_UNVERIFIED) 89 { 90 $query = array( 91 'UPDATE' => 'users', 92 'SET' => 'group_id='.$forum_config['o_default_user_group'], 93 'WHERE' => 'id='.$user_id 94 ); 95 96 ($hook = get_hook('li_login_qr_update_user_group')) ? eval($hook) : null; 97 $forum_db->query_build($query) or error(__FILE__, __LINE__); 98 99 // Remove cache file with forum stats 100 if (!defined('FORUM_CACHE_FUNCTIONS_LOADED')) 101 { 102 require FORUM_ROOT.'include/cache.php'; 103 } 104 105 clean_stats_cache(); 106 } 107 108 // Remove this user's guest entry from the online list 109 $query = array( 110 'DELETE' => 'online', 111 'WHERE' => 'ident=\''.$forum_db->escape(get_remote_address()).'\'' 112 ); 113 114 ($hook = get_hook('li_login_qr_delete_online_user')) ? eval($hook) : null; 115 $forum_db->query_build($query) or error(__FILE__, __LINE__); 116 117 $expire = ($save_pass) ? time() + 1209600 : time() + $forum_config['o_timeout_visit']; 118 forum_setcookie($cookie_name, base64_encode($user_id.'|'.$form_password_hash.'|'.$expire.'|'.sha1($salt.$form_password_hash.forum_hash($expire, $salt))), $expire); 119 120 ($hook = get_hook('li_login_pre_redirect')) ? eval($hook) : null; 121 122 redirect(forum_htmlencode($_POST['redirect_url']).((substr_count($_POST['redirect_url'], '?') == 1) ? '&' : '?').'login=1', $lang_login['Login redirect']); 123 } 124} 125 126 127// Logout 128else if ($action == 'out') 129{ 130 if ($forum_user['is_guest'] || !isset($_GET['id']) || $_GET['id'] != $forum_user['id']) 131 { 132 header('Location: '.forum_link($forum_url['index'])); 133 exit; 134 } 135 136 // We validate the CSRF token. If it's set in POST and we're at this point, the token is valid. 137 // If it's in GET, we need to make sure it's valid. 138 if (!isset($_POST['csrf_token']) && (!isset($_GET['csrf_token']) || $_GET['csrf_token'] !== generate_form_token('logout'.$forum_user['id']))) 139 csrf_confirm_form(); 140 141 ($hook = get_hook('li_logout_selected')) ? eval($hook) : null; 142 143 // Remove user from "users online" list. 144 $query = array( 145 'DELETE' => 'online', 146 'WHERE' => 'user_id='.$forum_user['id'] 147 ); 148 149 ($hook = get_hook('li_logout_qr_delete_online_user')) ? eval($hook) : null; 150 $forum_db->query_build($query) or error(__FILE__, __LINE__); 151 152 // Update last_visit (make sure there's something to update it with) 153 if (isset($forum_user['logged'])) 154 { 155 $query = array( 156 'UPDATE' => 'users', 157 'SET' => 'last_visit='.$forum_user['logged'], 158 'WHERE' => 'id='.$forum_user['id'] 159 ); 160 161 ($hook = get_hook('li_logout_qr_update_last_visit')) ? eval($hook) : null; 162 $forum_db->query_build($query) or error(__FILE__, __LINE__); 163 } 164 165 $expire = time() + 1209600; 166 forum_setcookie($cookie_name, base64_encode('1|'.random_key(8, false, true).'|'.$expire.'|'.random_key(8, false, true)), $expire); 167 168 // Reset tracked topics 169 set_tracked_topics(null); 170 171 ($hook = get_hook('li_logout_pre_redirect')) ? eval($hook) : null; 172 173 redirect(forum_link($forum_url['index']), $lang_login['Logout redirect']); 174} 175 176 177// New password 178else if ($action == 'forget' || $action == 'forget_2') 179{ 180 if (!$forum_user['is_guest']) 181 header('Location: '.forum_link($forum_url['index'])); 182 183 ($hook = get_hook('li_forgot_pass_selected')) ? eval($hook) : null; 184 185 if (isset($_POST['form_sent'])) 186 { 187 // User pressed the cancel button 188 if (isset($_POST['cancel'])) 189 redirect(forum_link($forum_url['index']), $lang_login['New password cancel redirect']); 190 191 if (!defined('FORUM_EMAIL_FUNCTIONS_LOADED')) 192 require FORUM_ROOT.'include/email.php'; 193 194 // Validate the email-address 195 $email = strtolower(forum_trim($_POST['req_email'])); 196 if (!is_valid_email($email)) 197 $errors[] = $lang_login['Invalid e-mail']; 198 199 ($hook = get_hook('li_forgot_pass_end_validation')) ? eval($hook) : null; 200 201 // Did everything go according to plan? 202 if (empty($errors)) 203 { 204 $users_with_email = array(); 205 206 // Fetch user matching $email 207 $query = array( 208 'SELECT' => 'u.id, u.group_id, u.username, u.salt, u.last_email_sent', 209 'FROM' => 'users AS u', 210 'WHERE' => 'u.email=\''.$forum_db->escape($email).'\'' 211 ); 212 213 ($hook = get_hook('li_forgot_pass_qr_get_user_data')) ? eval($hook) : null; 214 $result = $forum_db->query_build($query) or error(__FILE__, __LINE__); 215 216 while ($cur_user = $forum_db->fetch_assoc($result)) 217 { 218 $users_with_email[] = $cur_user; 219 } 220 221 if (!empty($users_with_email)) 222 { 223 ($hook = get_hook('li_forgot_pass_pre_email')) ? eval($hook) : null; 224 225 // Load the "activate password" template 226 $mail_tpl = forum_trim(file_get_contents(FORUM_ROOT.'lang/'.$forum_user['language'].'/mail_templates/activate_password.tpl')); 227 228 // The first row contains the subject 229 $first_crlf = strpos($mail_tpl, "\n"); 230 $mail_subject = forum_trim(substr($mail_tpl, 8, $first_crlf-8)); 231 $mail_message = forum_trim(substr($mail_tpl, $first_crlf)); 232 233 // Do the generic replacements first (they apply to all e-mails sent out here) 234 $mail_message = str_replace('<base_url>', $base_url.'/', $mail_message); 235 $mail_message = str_replace('<board_mailer>', sprintf($lang_common['Forum mailer'], $forum_config['o_board_title']), $mail_message); 236 237 ($hook = get_hook('li_forgot_pass_new_general_replace_data')) ? eval($hook) : null; 238 239 // Loop through users we found 240 foreach ($users_with_email as $cur_hit) 241 { 242 $forgot_pass_timeout = 3600; 243 244 ($hook = get_hook('li_forgot_pass_pre_flood_check')) ? eval($hook) : null; 245 246 if ($cur_hit['group_id'] == FORUM_ADMIN) 247 message(sprintf($lang_login['Email important'], '<a href="mailto:'.forum_htmlencode($forum_config['o_admin_email']).'">'.forum_htmlencode($forum_config['o_admin_email']).'</a>')); 248 249 if ($cur_hit['last_email_sent'] != '' && (time() - $cur_hit['last_email_sent']) < $forgot_pass_timeout && (time() - $cur_hit['last_email_sent']) >= 0) 250 message(sprintf($lang_login['Email flood'], $forgot_pass_timeout)); 251 252 // Generate a new password activation key 253 $new_password_key = random_key(8, true); 254 255 $query = array( 256 'UPDATE' => 'users', 257 'SET' => 'activate_key=\''.$new_password_key.'\', last_email_sent = '.time(), 258 'WHERE' => 'id='.$cur_hit['id'] 259 ); 260 261 ($hook = get_hook('li_forgot_pass_qr_set_activate_key')) ? eval($hook) : null; 262 $forum_db->query_build($query) or error(__FILE__, __LINE__); 263 264 // Do the user specific replacements to the template 265 $cur_mail_message = str_replace('<username>', $cur_hit['username'], $mail_message); 266 $cur_mail_message = str_replace('<activation_url>', str_replace('&', '&', forum_link($forum_url['change_password_key'], array($cur_hit['id'], $new_password_key))), $cur_mail_message); 267 268 ($hook = get_hook('li_forgot_pass_new_user_replace_data')) ? eval($hook) : null; 269 270 forum_mail($email, $mail_subject, $cur_mail_message); 271 } 272 273 message(sprintf($lang_login['Forget mail'], '<a href="mailto:'.forum_htmlencode($forum_config['o_admin_email']).'">'.forum_htmlencode($forum_config['o_admin_email']).'</a>')); 274 } 275 else 276 $errors[] = sprintf($lang_login['No e-mail match'], forum_htmlencode($email)); 277 } 278 } 279 280 // Setup form 281 $forum_page['group_count'] = $forum_page['item_count'] = $forum_page['fld_count'] = 0; 282 $forum_page['form_action'] = forum_link($forum_url['request_password']); 283 284 // Setup breadcrumbs 285 $forum_page['crumbs'] = array( 286 array($forum_config['o_board_title'], forum_link($forum_url['index'])), 287 $lang_login['New password request'] 288 ); 289 290 ($hook = get_hook('li_forgot_pass_pre_header_load')) ? eval($hook) : null; 291 292 define ('FORUM_PAGE', 'reqpass'); 293 require FORUM_ROOT.'header.php'; 294 295 // START SUBST - <!-- forum_main --> 296 ob_start(); 297 298 ($hook = get_hook('li_forgot_pass_output_start')) ? eval($hook) : null; 299 300?> 301 <div class="main-head"> 302 <h2 class="hn"><span><?php echo $lang_login['New password request'] ?></span></h2> 303 </div> 304 <div class="main-content main-frm"> 305 <div class="ct-box info-box"> 306 <p class="important"><?php echo $lang_login['New password info'] ?></p> 307 </div> 308<?php 309 310 // If there were any errors, show them 311 if (!empty($errors)) 312 { 313 $forum_page['errors'] = array(); 314 foreach ($errors as $cur_error) 315 $forum_page['errors'][] = '<li class="warn"><span>'.$cur_error.'</span></li>'; 316 317 ($hook = get_hook('li_forgot_pass_pre_new_password_errors')) ? eval($hook) : null; 318 319?> 320 <div class="ct-box error-box"> 321 <h2 class="warn hn"><?php echo $lang_login['New password errors'] ?></h2> 322 <ul class="error-list"> 323 <?php echo implode("\n\t\t\t\t", $forum_page['errors'])."\n" ?> 324 </ul> 325 </div> 326<?php 327 328 } 329 330?> 331 <div id="req-msg" class="req-warn ct-box error-box"> 332 <p class="important"><?php echo $lang_common['Required warn'] ?></p> 333 </div> 334 <form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $forum_page['form_action'] ?>"> 335 <div class="hidden"> 336 <input type="hidden" name="form_sent" value="1" /> 337 <input type="hidden" name="csrf_token" value="<?php echo generate_form_token($forum_page['form_action']) ?>" /> 338 </div> 339<?php ($hook = get_hook('li_forgot_pass_pre_group')) ? eval($hook) : null; ?> 340 <div class="frm-group group<?php echo ++$forum_page['group_count'] ?>"> 341<?php ($hook = get_hook('li_forgot_pass_pre_email')) ? eval($hook) : null; ?> 342 <div class="sf-set set<?php echo ++$forum_page['item_count'] ?>"> 343 <div class="sf-box text required"> 344 <label for="fld<?php echo ++$forum_page['fld_count'] ?>"><span><?php echo $lang_login['E-mail address'] ?></span> <small><?php echo $lang_login['E-mail address help'] ?></small></label><br /> 345 <span class="fld-input"><input id="fld<?php echo $forum_page['fld_count'] ?>" type="email" name="req_email" value="<?php if (isset($_POST['req_email'])) echo forum_htmlencode($_POST['req_email']); ?>" size="35" maxlength="80" required spellcheck="false" /></span> 346 </div> 347 </div> 348<?php ($hook = get_hook('li_forgot_pass_pre_group_end')) ? eval($hook) : null; ?> 349 </div> 350<?php ($hook = get_hook('li_forgot_pass_group_end')) ? eval($hook) : null; ?> 351 <div class="frm-buttons"> 352 <span class="submit primary"><input type="submit" name="request_pass" value="<?php echo $lang_login['Submit password request'] ?>" /></span> 353 <span class="cancel"><input type="submit" name="cancel" value="<?php echo $lang_common['Cancel'] ?>" formnovalidate /></span> 354 </div> 355 </form> 356 </div> 357<?php 358 359 ($hook = get_hook('li_forgot_pass_end')) ? eval($hook) : null; 360 361 $tpl_temp = forum_trim(ob_get_contents()); 362 $tpl_main = str_replace('<!-- forum_main -->', $tpl_temp, $tpl_main); 363 ob_end_clean(); 364 // END SUBST - <!-- forum_main --> 365 366 require FORUM_ROOT.'footer.php'; 367} 368 369if (!$forum_user['is_guest']) 370 header('Location: '.forum_link($forum_url['index'])); 371 372// Setup form 373$forum_page['group_count'] = $forum_page['item_count'] = $forum_page['fld_count'] = 0; 374$forum_page['form_action'] = forum_link($forum_url['login']); 375 376$forum_page['hidden_fields'] = array( 377 'form_sent' => '<input type="hidden" name="form_sent" value="1" />', 378 'redirect_url' => '<input type="hidden" name="redirect_url" value="'.forum_htmlencode($forum_user['prev_url']).'" />', 379 'csrf_token' => '<input type="hidden" name="csrf_token" value="'.generate_form_token($forum_page['form_action']).'" />' 380); 381 382// Setup breadcrumbs 383$forum_page['crumbs'] = array( 384 array($forum_config['o_board_title'], forum_link($forum_url['index'])), 385 sprintf($lang_login['Login info'], $forum_config['o_board_title']) 386); 387 388($hook = get_hook('li_login_pre_header_load')) ? eval($hook) : null; 389 390define('FORUM_PAGE', 'login'); 391require FORUM_ROOT.'header.php'; 392 393// START SUBST - <!-- forum_main --> 394ob_start(); 395 396($hook = get_hook('li_login_output_start')) ? eval($hook) : null; 397 398?> 399 <div class="main-head"> 400 <h2 class="hn"><span><?php echo sprintf($lang_login['Login info'], $forum_config['o_board_title']) ?></span></h2> 401 </div> 402 <div class="main-content main-frm"> 403 <div class="content-head"> 404 <p class="hn"><?php printf($lang_login['Login options'], '<a href="'.forum_link($forum_url['register']).'">'.$lang_login['register'].'</a>', '<a href="'.forum_link($forum_url['request_password']).'">'.$lang_login['Obtain pass'].'</a>') ?></p> 405 </div> 406<?php 407 408 // If there were any errors, show them 409 if (!empty($errors)) 410 { 411 $forum_page['errors'] = array(); 412 foreach ($errors as $cur_error) 413 $forum_page['errors'][] = '<li class="warn"><span>'.$cur_error.'</span></li>'; 414 415 ($hook = get_hook('li_pre_login_errors')) ? eval($hook) : null; 416 417?> 418 <div class="ct-box error-box"> 419 <h2 class="warn hn"><?php echo $lang_login['Login errors'] ?></h2> 420 <ul class="error-list"> 421 <?php echo implode("\n\t\t\t\t", $forum_page['errors'])."\n" ?> 422 </ul> 423 </div> 424<?php 425 426 } 427 428?> 429 <div id="req-msg" class="req-warn ct-box error-box"> 430 <p class="important"><?php echo $lang_common['Required warn'] ?></p> 431 </div> 432 <form id="afocus" class="frm-form" method="post" accept-charset="utf-8" action="<?php echo $forum_page['form_action'] ?>"> 433 <div class="hidden"> 434 <?php echo implode("\n\t\t\t\t", $forum_page['hidden_fields'])."\n" ?> 435 </div> 436<?php ($hook = get_hook('li_login_pre_login_group')) ? eval($hook) : null; ?> 437 <div class="frm-group group<?php echo ++$forum_page['group_count'] ?>"> 438<?php ($hook = get_hook('li_login_pre_username')) ? eval($hook) : null; ?> 439 <div class="sf-set set<?php echo ++$forum_page['item_count'] ?>"> 440 <div class="sf-box text required"> 441 <label for="fld<?php echo ++$forum_page['fld_count'] ?>"><span><?php echo $lang_login['Username'] ?></span></label><br /> 442 <span class="fld-input"><input type="text" id="fld<?php echo $forum_page['fld_count'] ?>" name="req_username" value="<?php if (isset($_POST['req_username'])) echo forum_htmlencode($_POST['req_username']); ?>" size="35" maxlength="25" required spellcheck="false" /></span> 443 </div> 444 </div> 445<?php ($hook = get_hook('li_login_pre_pass')) ? eval($hook) : null; ?> 446 <div class="sf-set set<?php echo ++$forum_page['item_count'] ?>"> 447 <div class="sf-box text required"> 448 <label for="fld<?php echo ++$forum_page['fld_count'] ?>"><span><?php echo $lang_login['Password'] ?></span></label><br /> 449 <span class="fld-input"><input type="password" id="fld<?php echo $forum_page['fld_count'] ?>" name="req_password" value="<?php if (isset($_POST['req_password'])) echo forum_htmlencode($_POST['req_password']); ?>" size="35" required /></span> 450 </div> 451 </div> 452<?php ($hook = get_hook('li_login_pre_remember_me_checkbox')) ? eval($hook) : null; ?> 453 <div class="sf-set set<?php echo ++$forum_page['item_count'] ?>"> 454 <div class="sf-box checkbox"> 455 <span class="fld-input"><input type="checkbox" id="fld<?php echo ++$forum_page['fld_count'] ?>" name="save_pass" value="1"<?php if (isset($_POST['save_pass'])) echo ' checked="checked"'; ?> /></span> 456 <label for="fld<?php echo $forum_page['fld_count'] ?>"><?php echo $lang_login['Remember me'] ?></label> 457 </div> 458 </div> 459<?php ($hook = get_hook('li_login_pre_group_end')) ? eval($hook) : null; ?> 460 </div> 461<?php ($hook = get_hook('li_login_group_end')) ? eval($hook) : null; ?> 462 <div class="frm-buttons"> 463 <span class="submit primary"><input type="submit" name="login" value="<?php echo $lang_login['Login'] ?>" /></span> 464 </div> 465 </form> 466 </div> 467<?php 468 469($hook = get_hook('li_end')) ? eval($hook) : null; 470 471$tpl_temp = forum_trim(ob_get_contents()); 472$tpl_main = str_replace('<!-- forum_main -->', $tpl_temp, $tpl_main); 473ob_end_clean(); 474// END SUBST - <!-- forum_main --> 475 476require FORUM_ROOT.'footer.php'; 477