Yoshi2889 /
SMF2.1
| 1 | <?php |
||
| 2 | |||
| 3 | /** |
||
| 4 | * This file has the very important job of ensuring forum security. |
||
| 5 | * This task includes banning and permissions, namely. |
||
| 6 | * |
||
| 7 | * Simple Machines Forum (SMF) |
||
| 8 | * |
||
| 9 | * @package SMF |
||
| 10 | * @author Simple Machines https://www.simplemachines.org |
||
| 11 | * @copyright 2020 Simple Machines and individual contributors |
||
| 12 | * @license https://www.simplemachines.org/about/smf/license.php BSD |
||
| 13 | * |
||
| 14 | * @version 2.1 RC2 |
||
| 15 | */ |
||
| 16 | |||
| 17 | if (!defined('SMF')) |
||
| 18 | die('No direct access...'); |
||
| 19 | |||
| 20 | /** |
||
| 21 | * Check if the user is who he/she says he is |
||
| 22 | * Makes sure the user is who they claim to be by requiring a password to be typed in every hour. |
||
| 23 | * Is turned on and off by the securityDisable setting. |
||
| 24 | * Uses the adminLogin() function of Subs-Auth.php if they need to login, which saves all request (post and get) data. |
||
| 25 | * |
||
| 26 | * @param string $type What type of session this is |
||
| 27 | * @param string $force When true, require a password even if we normally wouldn't |
||
| 28 | * @return void|string Returns 'session_verify_fail' if verification failed |
||
| 29 | */ |
||
| 30 | function validateSession($type = 'admin', $force = false) |
||
| 31 | { |
||
| 32 | global $modSettings, $sourcedir, $user_info; |
||
| 33 | |||
| 34 | // We don't care if the option is off, because Guests should NEVER get past here. |
||
| 35 | is_not_guest(); |
||
| 36 | |||
| 37 | // Validate what type of session check this is. |
||
| 38 | $types = array(); |
||
| 39 | call_integration_hook('integrate_validateSession', array(&$types)); |
||
| 40 | $type = in_array($type, $types) || $type == 'moderate' ? $type : 'admin'; |
||
| 41 | |||
| 42 | // If we're using XML give an additional ten minutes grace as an admin can't log on in XML mode. |
||
| 43 | $refreshTime = isset($_GET['xml']) ? 4200 : 3600; |
||
| 44 | |||
| 45 | if (empty($force)) |
||
| 46 | { |
||
| 47 | // Is the security option off? |
||
| 48 | if (!empty($modSettings['securityDisable' . ($type != 'admin' ? '_' . $type : '')])) |
||
| 49 | return; |
||
| 50 | |||
| 51 | // Or are they already logged in?, Moderator or admin session is need for this area |
||
| 52 | if ((!empty($_SESSION[$type . '_time']) && $_SESSION[$type . '_time'] + $refreshTime >= time()) || (!empty($_SESSION['admin_time']) && $_SESSION['admin_time'] + $refreshTime >= time())) |
||
| 53 | return; |
||
| 54 | } |
||
| 55 | |||
| 56 | require_once($sourcedir . '/Subs-Auth.php'); |
||
| 57 | |||
| 58 | // Posting the password... check it. |
||
| 59 | if (isset($_POST[$type . '_pass'])) |
||
| 60 | { |
||
| 61 | // Check to ensure we're forcing SSL for authentication |
||
| 62 | if (!empty($modSettings['force_ssl']) && empty($maintenance) && !httpsOn()) |
||
| 63 | fatal_lang_error('login_ssl_required'); |
||
| 64 | |||
| 65 | checkSession(); |
||
| 66 | |||
| 67 | $good_password = in_array(true, call_integration_hook('integrate_verify_password', array($user_info['username'], $_POST[$type . '_pass'], false)), true); |
||
| 68 | |||
| 69 | // Password correct? |
||
| 70 | if ($good_password || hash_verify_password($user_info['username'], $_POST[$type . '_pass'], $user_info['passwd'])) |
||
| 71 | { |
||
| 72 | $_SESSION[$type . '_time'] = time(); |
||
| 73 | unset($_SESSION['request_referer']); |
||
| 74 | return; |
||
| 75 | } |
||
| 76 | } |
||
| 77 | |||
| 78 | // Better be sure to remember the real referer |
||
| 79 | if (empty($_SESSION['request_referer'])) |
||
| 80 | $_SESSION['request_referer'] = isset($_SERVER['HTTP_REFERER']) ? @parse_url($_SERVER['HTTP_REFERER']) : array(); |
||
| 81 | elseif (empty($_POST)) |
||
| 82 | unset($_SESSION['request_referer']); |
||
| 83 | |||
| 84 | // Need to type in a password for that, man. |
||
| 85 | if (!isset($_GET['xml'])) |
||
| 86 | adminLogin($type); |
||
| 87 | else |
||
| 88 | return 'session_verify_fail'; |
||
| 89 | } |
||
| 90 | |||
| 91 | /** |
||
| 92 | * Require a user who is logged in. (not a guest.) |
||
| 93 | * Checks if the user is currently a guest, and if so asks them to login with a message telling them why. |
||
| 94 | * Message is what to tell them when asking them to login. |
||
| 95 | * |
||
| 96 | * @param string $message The message to display to the guest |
||
| 97 | */ |
||
| 98 | function is_not_guest($message = '') |
||
| 99 | { |
||
| 100 | global $user_info, $txt, $context, $scripturl, $modSettings; |
||
| 101 | |||
| 102 | // Luckily, this person isn't a guest. |
||
| 103 | if (!$user_info['is_guest']) |
||
| 104 | return; |
||
| 105 | |||
| 106 | // Log what they were trying to do didn't work) |
||
| 107 | if (!empty($modSettings['who_enabled'])) |
||
| 108 | $_GET['error'] = 'guest_login'; |
||
| 109 | writeLog(true); |
||
| 110 | |||
| 111 | // Just die. |
||
| 112 | if (isset($_REQUEST['xml'])) |
||
| 113 | obExit(false); |
||
| 114 | |||
| 115 | // Attempt to detect if they came from dlattach. |
||
| 116 | if (SMF != 'SSI' && empty($context['theme_loaded'])) |
||
| 117 | loadTheme(); |
||
| 118 | |||
| 119 | // Never redirect to an attachment |
||
| 120 | if (strpos($_SERVER['REQUEST_URL'], 'dlattach') === false) |
||
| 121 | $_SESSION['login_url'] = $_SERVER['REQUEST_URL']; |
||
| 122 | |||
| 123 | // Load the Login template and language file. |
||
| 124 | loadLanguage('Login'); |
||
| 125 | |||
| 126 | // Apparently we're not in a position to handle this now. Let's go to a safer location for now. |
||
| 127 | if (empty($context['template_layers'])) |
||
| 128 | { |
||
| 129 | $_SESSION['login_url'] = $scripturl . '?' . $_SERVER['QUERY_STRING']; |
||
| 130 | redirectexit('action=login'); |
||
| 131 | } |
||
| 132 | else |
||
| 133 | { |
||
| 134 | loadTemplate('Login'); |
||
| 135 | $context['sub_template'] = 'kick_guest'; |
||
| 136 | $context['robot_no_index'] = true; |
||
| 137 | } |
||
| 138 | |||
| 139 | // Use the kick_guest sub template... |
||
| 140 | $context['kick_message'] = $message; |
||
| 141 | $context['page_title'] = $txt['login']; |
||
| 142 | |||
| 143 | obExit(); |
||
| 144 | |||
| 145 | // We should never get to this point, but if we did we wouldn't know the user isn't a guest. |
||
| 146 | trigger_error('Hacking attempt...', E_USER_ERROR); |
||
| 147 | } |
||
| 148 | |||
| 149 | /** |
||
| 150 | * Do banning related stuff. (ie. disallow access....) |
||
| 151 | * Checks if the user is banned, and if so dies with an error. |
||
| 152 | * Caches this information for optimization purposes. |
||
| 153 | * |
||
| 154 | * @param bool $forceCheck Whether to force a recheck |
||
| 155 | */ |
||
| 156 | function is_not_banned($forceCheck = false) |
||
| 157 | { |
||
| 158 | global $txt, $modSettings, $context, $user_info; |
||
| 159 | global $sourcedir, $cookiename, $user_settings, $smcFunc; |
||
| 160 | |||
| 161 | // You cannot be banned if you are an admin - doesn't help if you log out. |
||
| 162 | if ($user_info['is_admin']) |
||
| 163 | return; |
||
| 164 | |||
| 165 | // Only check the ban every so often. (to reduce load.) |
||
| 166 | if ($forceCheck || !isset($_SESSION['ban']) || empty($modSettings['banLastUpdated']) || ($_SESSION['ban']['last_checked'] < $modSettings['banLastUpdated']) || $_SESSION['ban']['id_member'] != $user_info['id'] || $_SESSION['ban']['ip'] != $user_info['ip'] || $_SESSION['ban']['ip2'] != $user_info['ip2'] || (isset($user_info['email'], $_SESSION['ban']['email']) && $_SESSION['ban']['email'] != $user_info['email'])) |
||
| 167 | { |
||
| 168 | // Innocent until proven guilty. (but we know you are! :P) |
||
| 169 | $_SESSION['ban'] = array( |
||
| 170 | 'last_checked' => time(), |
||
| 171 | 'id_member' => $user_info['id'], |
||
| 172 | 'ip' => $user_info['ip'], |
||
| 173 | 'ip2' => $user_info['ip2'], |
||
| 174 | 'email' => $user_info['email'], |
||
| 175 | ); |
||
| 176 | |||
| 177 | $ban_query = array(); |
||
| 178 | $ban_query_vars = array('current_time' => time()); |
||
| 179 | $flag_is_activated = false; |
||
| 180 | |||
| 181 | // Check both IP addresses. |
||
| 182 | foreach (array('ip', 'ip2') as $ip_number) |
||
| 183 | { |
||
| 184 | if ($ip_number == 'ip2' && $user_info['ip2'] == $user_info['ip']) |
||
| 185 | continue; |
||
| 186 | $ban_query[] = ' {inet:' . $ip_number . '} BETWEEN bi.ip_low and bi.ip_high'; |
||
| 187 | $ban_query_vars[$ip_number] = $user_info[$ip_number]; |
||
| 188 | // IP was valid, maybe there's also a hostname... |
||
| 189 | if (empty($modSettings['disableHostnameLookup']) && $user_info[$ip_number] != 'unknown') |
||
| 190 | { |
||
| 191 | $hostname = host_from_ip($user_info[$ip_number]); |
||
| 192 | if (strlen($hostname) > 0) |
||
| 193 | { |
||
| 194 | $ban_query[] = '({string:hostname' . $ip_number . '} LIKE bi.hostname)'; |
||
| 195 | $ban_query_vars['hostname' . $ip_number] = $hostname; |
||
| 196 | } |
||
| 197 | } |
||
| 198 | } |
||
| 199 | |||
| 200 | // Is their email address banned? |
||
| 201 | if (strlen($user_info['email']) != 0) |
||
| 202 | { |
||
| 203 | $ban_query[] = '({string:email} LIKE bi.email_address)'; |
||
| 204 | $ban_query_vars['email'] = $user_info['email']; |
||
| 205 | } |
||
| 206 | |||
| 207 | // How about this user? |
||
| 208 | if (!$user_info['is_guest'] && !empty($user_info['id'])) |
||
| 209 | { |
||
| 210 | $ban_query[] = 'bi.id_member = {int:id_member}'; |
||
| 211 | $ban_query_vars['id_member'] = $user_info['id']; |
||
| 212 | } |
||
| 213 | |||
| 214 | // Check the ban, if there's information. |
||
| 215 | if (!empty($ban_query)) |
||
| 216 | { |
||
| 217 | $restrictions = array( |
||
| 218 | 'cannot_access', |
||
| 219 | 'cannot_login', |
||
| 220 | 'cannot_post', |
||
| 221 | 'cannot_register', |
||
| 222 | ); |
||
| 223 | $request = $smcFunc['db_query']('', ' |
||
| 224 | SELECT bi.id_ban, bi.email_address, bi.id_member, bg.cannot_access, bg.cannot_register, |
||
| 225 | bg.cannot_post, bg.cannot_login, bg.reason, COALESCE(bg.expire_time, 0) AS expire_time |
||
| 226 | FROM {db_prefix}ban_items AS bi |
||
| 227 | INNER JOIN {db_prefix}ban_groups AS bg ON (bg.id_ban_group = bi.id_ban_group AND (bg.expire_time IS NULL OR bg.expire_time > {int:current_time})) |
||
| 228 | WHERE |
||
| 229 | (' . implode(' OR ', $ban_query) . ')', |
||
| 230 | $ban_query_vars |
||
| 231 | ); |
||
| 232 | // Store every type of ban that applies to you in your session. |
||
| 233 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 234 | { |
||
| 235 | foreach ($restrictions as $restriction) |
||
| 236 | if (!empty($row[$restriction])) |
||
| 237 | { |
||
| 238 | $_SESSION['ban'][$restriction]['reason'] = $row['reason']; |
||
| 239 | $_SESSION['ban'][$restriction]['ids'][] = $row['id_ban']; |
||
| 240 | if (!isset($_SESSION['ban']['expire_time']) || ($_SESSION['ban']['expire_time'] != 0 && ($row['expire_time'] == 0 || $row['expire_time'] > $_SESSION['ban']['expire_time']))) |
||
| 241 | $_SESSION['ban']['expire_time'] = $row['expire_time']; |
||
| 242 | |||
| 243 | if (!$user_info['is_guest'] && $restriction == 'cannot_access' && ($row['id_member'] == $user_info['id'] || $row['email_address'] == $user_info['email'])) |
||
| 244 | $flag_is_activated = true; |
||
| 245 | } |
||
| 246 | } |
||
| 247 | $smcFunc['db_free_result']($request); |
||
| 248 | } |
||
| 249 | |||
| 250 | // Mark the cannot_access and cannot_post bans as being 'hit'. |
||
| 251 | if (isset($_SESSION['ban']['cannot_access']) || isset($_SESSION['ban']['cannot_post']) || isset($_SESSION['ban']['cannot_login'])) |
||
| 252 | log_ban(array_merge(isset($_SESSION['ban']['cannot_access']) ? $_SESSION['ban']['cannot_access']['ids'] : array(), isset($_SESSION['ban']['cannot_post']) ? $_SESSION['ban']['cannot_post']['ids'] : array(), isset($_SESSION['ban']['cannot_login']) ? $_SESSION['ban']['cannot_login']['ids'] : array())); |
||
| 253 | |||
| 254 | // If for whatever reason the is_activated flag seems wrong, do a little work to clear it up. |
||
| 255 | if ($user_info['id'] && (($user_settings['is_activated'] >= 10 && !$flag_is_activated) |
||
| 256 | || ($user_settings['is_activated'] < 10 && $flag_is_activated))) |
||
| 257 | { |
||
| 258 | require_once($sourcedir . '/ManageBans.php'); |
||
| 259 | updateBanMembers(); |
||
| 260 | } |
||
| 261 | } |
||
| 262 | |||
| 263 | // Hey, I know you! You're ehm... |
||
| 264 | if (!isset($_SESSION['ban']['cannot_access']) && !empty($_COOKIE[$cookiename . '_'])) |
||
| 265 | { |
||
| 266 | $bans = explode(',', $_COOKIE[$cookiename . '_']); |
||
| 267 | foreach ($bans as $key => $value) |
||
| 268 | $bans[$key] = (int) $value; |
||
| 269 | $request = $smcFunc['db_query']('', ' |
||
| 270 | SELECT bi.id_ban, bg.reason, COALESCE(bg.expire_time, 0) AS expire_time |
||
| 271 | FROM {db_prefix}ban_items AS bi |
||
| 272 | INNER JOIN {db_prefix}ban_groups AS bg ON (bg.id_ban_group = bi.id_ban_group) |
||
| 273 | WHERE bi.id_ban IN ({array_int:ban_list}) |
||
| 274 | AND (bg.expire_time IS NULL OR bg.expire_time > {int:current_time}) |
||
| 275 | AND bg.cannot_access = {int:cannot_access} |
||
| 276 | LIMIT {int:limit}', |
||
| 277 | array( |
||
| 278 | 'cannot_access' => 1, |
||
| 279 | 'ban_list' => $bans, |
||
| 280 | 'current_time' => time(), |
||
| 281 | 'limit' => count($bans), |
||
| 282 | ) |
||
| 283 | ); |
||
| 284 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 285 | { |
||
| 286 | $_SESSION['ban']['cannot_access']['ids'][] = $row['id_ban']; |
||
| 287 | $_SESSION['ban']['cannot_access']['reason'] = $row['reason']; |
||
| 288 | $_SESSION['ban']['expire_time'] = $row['expire_time']; |
||
| 289 | } |
||
| 290 | $smcFunc['db_free_result']($request); |
||
| 291 | |||
| 292 | // My mistake. Next time better. |
||
| 293 | if (!isset($_SESSION['ban']['cannot_access'])) |
||
| 294 | { |
||
| 295 | require_once($sourcedir . '/Subs-Auth.php'); |
||
| 296 | $cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies'])); |
||
| 297 | smf_setcookie($cookiename . '_', '', time() - 3600, $cookie_url[1], $cookie_url[0], false, false); |
||
| 298 | } |
||
| 299 | } |
||
| 300 | |||
| 301 | // If you're fully banned, it's end of the story for you. |
||
| 302 | if (isset($_SESSION['ban']['cannot_access'])) |
||
| 303 | { |
||
| 304 | // We don't wanna see you! |
||
| 305 | if (!$user_info['is_guest']) |
||
| 306 | $smcFunc['db_query']('', ' |
||
| 307 | DELETE FROM {db_prefix}log_online |
||
| 308 | WHERE id_member = {int:current_member}', |
||
| 309 | array( |
||
| 310 | 'current_member' => $user_info['id'], |
||
| 311 | ) |
||
| 312 | ); |
||
| 313 | |||
| 314 | // 'Log' the user out. Can't have any funny business... (save the name!) |
||
| 315 | $old_name = isset($user_info['name']) && $user_info['name'] != '' ? $user_info['name'] : $txt['guest_title']; |
||
| 316 | $user_info['name'] = ''; |
||
| 317 | $user_info['username'] = ''; |
||
| 318 | $user_info['is_guest'] = true; |
||
| 319 | $user_info['is_admin'] = false; |
||
| 320 | $user_info['permissions'] = array(); |
||
| 321 | $user_info['id'] = 0; |
||
| 322 | $context['user'] = array( |
||
| 323 | 'id' => 0, |
||
| 324 | 'username' => '', |
||
| 325 | 'name' => $txt['guest_title'], |
||
| 326 | 'is_guest' => true, |
||
| 327 | 'is_logged' => false, |
||
| 328 | 'is_admin' => false, |
||
| 329 | 'is_mod' => false, |
||
| 330 | 'can_mod' => false, |
||
| 331 | 'language' => $user_info['language'], |
||
| 332 | ); |
||
| 333 | |||
| 334 | // A goodbye present. |
||
| 335 | require_once($sourcedir . '/Subs-Auth.php'); |
||
| 336 | require_once($sourcedir . '/LogInOut.php'); |
||
| 337 | $cookie_url = url_parts(!empty($modSettings['localCookies']), !empty($modSettings['globalCookies'])); |
||
| 338 | smf_setcookie($cookiename . '_', implode(',', $_SESSION['ban']['cannot_access']['ids']), time() + 3153600, $cookie_url[1], $cookie_url[0], false, false); |
||
| 339 | |||
| 340 | // Don't scare anyone, now. |
||
| 341 | $_GET['action'] = ''; |
||
| 342 | $_GET['board'] = ''; |
||
| 343 | $_GET['topic'] = ''; |
||
| 344 | writeLog(true); |
||
| 345 | Logout(true, false); |
||
| 346 | |||
| 347 | // You banned, sucka! |
||
| 348 | fatal_error(sprintf($txt['your_ban'], $old_name) . (empty($_SESSION['ban']['cannot_access']['reason']) ? '' : '<br>' . $_SESSION['ban']['cannot_access']['reason']) . '<br>' . (!empty($_SESSION['ban']['expire_time']) ? sprintf($txt['your_ban_expires'], timeformat($_SESSION['ban']['expire_time'], false)) : $txt['your_ban_expires_never']), false); |
||
| 349 | |||
| 350 | // If we get here, something's gone wrong.... but let's try anyway. |
||
| 351 | trigger_error('Hacking attempt...', E_USER_ERROR); |
||
| 352 | } |
||
| 353 | // You're not allowed to log in but yet you are. Let's fix that. |
||
| 354 | elseif (isset($_SESSION['ban']['cannot_login']) && !$user_info['is_guest']) |
||
| 355 | { |
||
| 356 | // We don't wanna see you! |
||
| 357 | $smcFunc['db_query']('', ' |
||
| 358 | DELETE FROM {db_prefix}log_online |
||
| 359 | WHERE id_member = {int:current_member}', |
||
| 360 | array( |
||
| 361 | 'current_member' => $user_info['id'], |
||
| 362 | ) |
||
| 363 | ); |
||
| 364 | |||
| 365 | // 'Log' the user out. Can't have any funny business... (save the name!) |
||
| 366 | $old_name = isset($user_info['name']) && $user_info['name'] != '' ? $user_info['name'] : $txt['guest_title']; |
||
| 367 | $user_info['name'] = ''; |
||
| 368 | $user_info['username'] = ''; |
||
| 369 | $user_info['is_guest'] = true; |
||
| 370 | $user_info['is_admin'] = false; |
||
| 371 | $user_info['permissions'] = array(); |
||
| 372 | $user_info['id'] = 0; |
||
| 373 | $context['user'] = array( |
||
| 374 | 'id' => 0, |
||
| 375 | 'username' => '', |
||
| 376 | 'name' => $txt['guest_title'], |
||
| 377 | 'is_guest' => true, |
||
| 378 | 'is_logged' => false, |
||
| 379 | 'is_admin' => false, |
||
| 380 | 'is_mod' => false, |
||
| 381 | 'can_mod' => false, |
||
| 382 | 'language' => $user_info['language'], |
||
| 383 | ); |
||
| 384 | |||
| 385 | // SMF's Wipe 'n Clean(r) erases all traces. |
||
| 386 | $_GET['action'] = ''; |
||
| 387 | $_GET['board'] = ''; |
||
| 388 | $_GET['topic'] = ''; |
||
| 389 | writeLog(true); |
||
| 390 | |||
| 391 | require_once($sourcedir . '/LogInOut.php'); |
||
| 392 | Logout(true, false); |
||
| 393 | |||
| 394 | fatal_error(sprintf($txt['your_ban'], $old_name) . (empty($_SESSION['ban']['cannot_login']['reason']) ? '' : '<br>' . $_SESSION['ban']['cannot_login']['reason']) . '<br>' . (!empty($_SESSION['ban']['expire_time']) ? sprintf($txt['your_ban_expires'], timeformat($_SESSION['ban']['expire_time'], false)) : $txt['your_ban_expires_never']) . '<br>' . $txt['ban_continue_browse'], false); |
||
| 395 | } |
||
| 396 | |||
| 397 | // Fix up the banning permissions. |
||
| 398 | if (isset($user_info['permissions'])) |
||
| 399 | banPermissions(); |
||
| 400 | } |
||
| 401 | |||
| 402 | /** |
||
| 403 | * Fix permissions according to ban status. |
||
| 404 | * Applies any states of banning by removing permissions the user cannot have. |
||
| 405 | */ |
||
| 406 | function banPermissions() |
||
| 407 | { |
||
| 408 | global $user_info, $sourcedir, $modSettings, $context; |
||
| 409 | |||
| 410 | // Somehow they got here, at least take away all permissions... |
||
| 411 | if (isset($_SESSION['ban']['cannot_access'])) |
||
| 412 | $user_info['permissions'] = array(); |
||
| 413 | // Okay, well, you can watch, but don't touch a thing. |
||
| 414 | elseif (isset($_SESSION['ban']['cannot_post']) || (!empty($modSettings['warning_mute']) && $modSettings['warning_mute'] <= $user_info['warning'])) |
||
| 415 | { |
||
| 416 | $denied_permissions = array( |
||
| 417 | 'pm_send', |
||
| 418 | 'calendar_post', 'calendar_edit_own', 'calendar_edit_any', |
||
| 419 | 'poll_post', |
||
| 420 | 'poll_add_own', 'poll_add_any', |
||
| 421 | 'poll_edit_own', 'poll_edit_any', |
||
| 422 | 'poll_lock_own', 'poll_lock_any', |
||
| 423 | 'poll_remove_own', 'poll_remove_any', |
||
| 424 | 'manage_attachments', 'manage_smileys', 'manage_boards', 'admin_forum', 'manage_permissions', |
||
| 425 | 'moderate_forum', 'manage_membergroups', 'manage_bans', 'send_mail', 'edit_news', |
||
| 426 | 'profile_identity_any', 'profile_extra_any', 'profile_title_any', |
||
| 427 | 'profile_forum_any', 'profile_other_any', 'profile_signature_any', |
||
| 428 | 'post_new', 'post_reply_own', 'post_reply_any', |
||
| 429 | 'delete_own', 'delete_any', 'delete_replies', |
||
| 430 | 'make_sticky', |
||
| 431 | 'merge_any', 'split_any', |
||
| 432 | 'modify_own', 'modify_any', 'modify_replies', |
||
| 433 | 'move_any', |
||
| 434 | 'lock_own', 'lock_any', |
||
| 435 | 'remove_own', 'remove_any', |
||
| 436 | 'post_unapproved_topics', 'post_unapproved_replies_own', 'post_unapproved_replies_any', |
||
| 437 | ); |
||
| 438 | call_integration_hook('integrate_post_ban_permissions', array(&$denied_permissions)); |
||
| 439 | $user_info['permissions'] = array_diff($user_info['permissions'], $denied_permissions); |
||
| 440 | } |
||
| 441 | // Are they absolutely under moderation? |
||
| 442 | elseif (!empty($modSettings['warning_moderate']) && $modSettings['warning_moderate'] <= $user_info['warning']) |
||
| 443 | { |
||
| 444 | // Work out what permissions should change... |
||
| 445 | $permission_change = array( |
||
| 446 | 'post_new' => 'post_unapproved_topics', |
||
| 447 | 'post_reply_own' => 'post_unapproved_replies_own', |
||
| 448 | 'post_reply_any' => 'post_unapproved_replies_any', |
||
| 449 | 'post_attachment' => 'post_unapproved_attachments', |
||
| 450 | ); |
||
| 451 | call_integration_hook('integrate_warn_permissions', array(&$permission_change)); |
||
| 452 | foreach ($permission_change as $old => $new) |
||
| 453 | { |
||
| 454 | if (!in_array($old, $user_info['permissions'])) |
||
| 455 | unset($permission_change[$old]); |
||
| 456 | else |
||
| 457 | $user_info['permissions'][] = $new; |
||
| 458 | } |
||
| 459 | $user_info['permissions'] = array_diff($user_info['permissions'], array_keys($permission_change)); |
||
| 460 | } |
||
| 461 | |||
| 462 | // @todo Find a better place to call this? Needs to be after permissions loaded! |
||
| 463 | // Finally, some bits we cache in the session because it saves queries. |
||
| 464 | if (isset($_SESSION['mc']) && $_SESSION['mc']['time'] > $modSettings['settings_updated'] && $_SESSION['mc']['id'] == $user_info['id']) |
||
| 465 | $user_info['mod_cache'] = $_SESSION['mc']; |
||
| 466 | else |
||
| 467 | { |
||
| 468 | require_once($sourcedir . '/Subs-Auth.php'); |
||
| 469 | rebuildModCache(); |
||
| 470 | } |
||
| 471 | |||
| 472 | // Now that we have the mod cache taken care of lets setup a cache for the number of mod reports still open |
||
| 473 | if (isset($_SESSION['rc']['reports']) && isset($_SESSION['rc']['member_reports']) && $_SESSION['rc']['time'] > $modSettings['last_mod_report_action'] && $_SESSION['rc']['id'] == $user_info['id']) |
||
| 474 | { |
||
| 475 | $context['open_mod_reports'] = $_SESSION['rc']['reports']; |
||
| 476 | $context['open_member_reports'] = $_SESSION['rc']['member_reports']; |
||
| 477 | } |
||
| 478 | elseif ($_SESSION['mc']['bq'] != '0=1') |
||
| 479 | { |
||
| 480 | require_once($sourcedir . '/Subs-ReportedContent.php'); |
||
| 481 | $context['open_mod_reports'] = recountOpenReports('posts'); |
||
| 482 | $context['open_member_reports'] = recountOpenReports('members'); |
||
| 483 | } |
||
| 484 | else |
||
| 485 | { |
||
| 486 | $context['open_mod_reports'] = 0; |
||
| 487 | $context['open_member_reports'] = 0; |
||
| 488 | } |
||
| 489 | } |
||
| 490 | |||
| 491 | /** |
||
| 492 | * Log a ban in the database. |
||
| 493 | * Log the current user in the ban logs. |
||
| 494 | * Increment the hit counters for the specified ban ID's (if any.) |
||
| 495 | * |
||
| 496 | * @param array $ban_ids The IDs of the bans |
||
| 497 | * @param string $email The email address associated with the user that triggered this hit |
||
| 498 | */ |
||
| 499 | function log_ban($ban_ids = array(), $email = null) |
||
| 500 | { |
||
| 501 | global $user_info, $smcFunc; |
||
| 502 | |||
| 503 | // Don't log web accelerators, it's very confusing... |
||
| 504 | if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') |
||
| 505 | return; |
||
| 506 | |||
| 507 | $smcFunc['db_insert']('', |
||
| 508 | '{db_prefix}log_banned', |
||
| 509 | array('id_member' => 'int', 'ip' => 'inet', 'email' => 'string', 'log_time' => 'int'), |
||
| 510 | array($user_info['id'], $user_info['ip'], ($email === null ? ($user_info['is_guest'] ? '' : $user_info['email']) : $email), time()), |
||
| 511 | array('id_ban_log') |
||
| 512 | ); |
||
| 513 | |||
| 514 | // One extra point for these bans. |
||
| 515 | if (!empty($ban_ids)) |
||
| 516 | $smcFunc['db_query']('', ' |
||
| 517 | UPDATE {db_prefix}ban_items |
||
| 518 | SET hits = hits + 1 |
||
| 519 | WHERE id_ban IN ({array_int:ban_ids})', |
||
| 520 | array( |
||
| 521 | 'ban_ids' => $ban_ids, |
||
| 522 | ) |
||
| 523 | ); |
||
| 524 | } |
||
| 525 | |||
| 526 | /** |
||
| 527 | * Checks if a given email address might be banned. |
||
| 528 | * Check if a given email is banned. |
||
| 529 | * Performs an immediate ban if the turns turns out positive. |
||
| 530 | * |
||
| 531 | * @param string $email The email to check |
||
| 532 | * @param string $restriction What type of restriction (cannot_post, cannot_register, etc.) |
||
| 533 | * @param string $error The error message to display if they are indeed banned |
||
| 534 | */ |
||
| 535 | function isBannedEmail($email, $restriction, $error) |
||
| 536 | { |
||
| 537 | global $txt, $smcFunc; |
||
| 538 | |||
| 539 | // Can't ban an empty email |
||
| 540 | if (empty($email) || trim($email) == '') |
||
| 541 | return; |
||
| 542 | |||
| 543 | // Let's start with the bans based on your IP/hostname/memberID... |
||
| 544 | $ban_ids = isset($_SESSION['ban'][$restriction]) ? $_SESSION['ban'][$restriction]['ids'] : array(); |
||
| 545 | $ban_reason = isset($_SESSION['ban'][$restriction]) ? $_SESSION['ban'][$restriction]['reason'] : ''; |
||
| 546 | |||
| 547 | // ...and add to that the email address you're trying to register. |
||
| 548 | $request = $smcFunc['db_query']('', ' |
||
| 549 | SELECT bi.id_ban, bg.' . $restriction . ', bg.cannot_access, bg.reason |
||
| 550 | FROM {db_prefix}ban_items AS bi |
||
| 551 | INNER JOIN {db_prefix}ban_groups AS bg ON (bg.id_ban_group = bi.id_ban_group) |
||
| 552 | WHERE {string:email} LIKE bi.email_address |
||
| 553 | AND (bg.' . $restriction . ' = {int:cannot_access} OR bg.cannot_access = {int:cannot_access}) |
||
| 554 | AND (bg.expire_time IS NULL OR bg.expire_time >= {int:now})', |
||
| 555 | array( |
||
| 556 | 'email' => $email, |
||
| 557 | 'cannot_access' => 1, |
||
| 558 | 'now' => time(), |
||
| 559 | ) |
||
| 560 | ); |
||
| 561 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 562 | { |
||
| 563 | if (!empty($row['cannot_access'])) |
||
| 564 | { |
||
| 565 | $_SESSION['ban']['cannot_access']['ids'][] = $row['id_ban']; |
||
| 566 | $_SESSION['ban']['cannot_access']['reason'] = $row['reason']; |
||
| 567 | } |
||
| 568 | if (!empty($row[$restriction])) |
||
| 569 | { |
||
| 570 | $ban_ids[] = $row['id_ban']; |
||
| 571 | $ban_reason = $row['reason']; |
||
| 572 | } |
||
| 573 | } |
||
| 574 | $smcFunc['db_free_result']($request); |
||
| 575 | |||
| 576 | // You're in biiig trouble. Banned for the rest of this session! |
||
| 577 | if (isset($_SESSION['ban']['cannot_access'])) |
||
| 578 | { |
||
| 579 | log_ban($_SESSION['ban']['cannot_access']['ids']); |
||
| 580 | $_SESSION['ban']['last_checked'] = time(); |
||
| 581 | |||
| 582 | fatal_error(sprintf($txt['your_ban'], $txt['guest_title']) . $_SESSION['ban']['cannot_access']['reason'], false); |
||
| 583 | } |
||
| 584 | |||
| 585 | if (!empty($ban_ids)) |
||
| 586 | { |
||
| 587 | // Log this ban for future reference. |
||
| 588 | log_ban($ban_ids, $email); |
||
| 589 | fatal_error($error . $ban_reason, false); |
||
| 590 | } |
||
| 591 | } |
||
| 592 | |||
| 593 | /** |
||
| 594 | * Make sure the user's correct session was passed, and they came from here. |
||
| 595 | * Checks the current session, verifying that the person is who he or she should be. |
||
| 596 | * Also checks the referrer to make sure they didn't get sent here. |
||
| 597 | * Depends on the disableCheckUA setting, which is usually missing. |
||
| 598 | * Will check GET, POST, or REQUEST depending on the passed type. |
||
| 599 | * Also optionally checks the referring action if passed. (note that the referring action must be by GET.) |
||
| 600 | * |
||
| 601 | * @param string $type The type of check (post, get, request) |
||
| 602 | * @param string $from_action The action this is coming from |
||
| 603 | * @param bool $is_fatal Whether to die with a fatal error if the check fails |
||
| 604 | * @return string The error message if is_fatal is false. |
||
| 605 | */ |
||
| 606 | function checkSession($type = 'post', $from_action = '', $is_fatal = true) |
||
| 607 | { |
||
| 608 | global $sc, $modSettings, $boardurl; |
||
| 609 | |||
| 610 | // Is it in as $_POST['sc']? |
||
| 611 | if ($type == 'post') |
||
| 612 | { |
||
| 613 | $check = isset($_POST[$_SESSION['session_var']]) ? $_POST[$_SESSION['session_var']] : (empty($modSettings['strictSessionCheck']) && isset($_POST['sc']) ? $_POST['sc'] : null); |
||
| 614 | if ($check !== $sc) |
||
| 615 | $error = 'session_timeout'; |
||
| 616 | } |
||
| 617 | |||
| 618 | // How about $_GET['sesc']? |
||
| 619 | elseif ($type == 'get') |
||
| 620 | { |
||
| 621 | $check = isset($_GET[$_SESSION['session_var']]) ? $_GET[$_SESSION['session_var']] : (empty($modSettings['strictSessionCheck']) && isset($_GET['sesc']) ? $_GET['sesc'] : null); |
||
| 622 | if ($check !== $sc) |
||
| 623 | $error = 'session_verify_fail'; |
||
| 624 | } |
||
| 625 | |||
| 626 | // Or can it be in either? |
||
| 627 | elseif ($type == 'request') |
||
| 628 | { |
||
| 629 | $check = isset($_GET[$_SESSION['session_var']]) ? $_GET[$_SESSION['session_var']] : (empty($modSettings['strictSessionCheck']) && isset($_GET['sesc']) ? $_GET['sesc'] : (isset($_POST[$_SESSION['session_var']]) ? $_POST[$_SESSION['session_var']] : (empty($modSettings['strictSessionCheck']) && isset($_POST['sc']) ? $_POST['sc'] : null))); |
||
| 630 | |||
| 631 | if ($check !== $sc) |
||
| 632 | $error = 'session_verify_fail'; |
||
| 633 | } |
||
| 634 | |||
| 635 | // Verify that they aren't changing user agents on us - that could be bad. |
||
| 636 | if ((!isset($_SESSION['USER_AGENT']) || $_SESSION['USER_AGENT'] != $_SERVER['HTTP_USER_AGENT']) && empty($modSettings['disableCheckUA'])) |
||
| 637 | $error = 'session_verify_fail'; |
||
| 638 | |||
| 639 | // Make sure a page with session check requirement is not being prefetched. |
||
| 640 | if (isset($_SERVER['HTTP_X_MOZ']) && $_SERVER['HTTP_X_MOZ'] == 'prefetch') |
||
| 641 | { |
||
| 642 | ob_end_clean(); |
||
| 643 | send_http_status(403); |
||
| 644 | die; |
||
|
0 ignored issues
–
show
|
|||
| 645 | } |
||
| 646 | |||
| 647 | // Check the referring site - it should be the same server at least! |
||
| 648 | if (isset($_SESSION['request_referer'])) |
||
| 649 | $referrer = $_SESSION['request_referer']; |
||
| 650 | else |
||
| 651 | $referrer = isset($_SERVER['HTTP_REFERER']) ? @parse_url($_SERVER['HTTP_REFERER']) : array(); |
||
| 652 | if (!empty($referrer['host'])) |
||
| 653 | { |
||
| 654 | if (strpos($_SERVER['HTTP_HOST'], ':') !== false) |
||
| 655 | $real_host = substr($_SERVER['HTTP_HOST'], 0, strpos($_SERVER['HTTP_HOST'], ':')); |
||
| 656 | else |
||
| 657 | $real_host = $_SERVER['HTTP_HOST']; |
||
| 658 | |||
| 659 | $parsed_url = parse_url($boardurl); |
||
| 660 | |||
| 661 | // Are global cookies on? If so, let's check them ;). |
||
| 662 | if (!empty($modSettings['globalCookies'])) |
||
| 663 | { |
||
| 664 | if (preg_match('~(?:[^\.]+\.)?([^\.]{3,}\..+)\z~i', $parsed_url['host'], $parts) == 1) |
||
| 665 | $parsed_url['host'] = $parts[1]; |
||
| 666 | |||
| 667 | if (preg_match('~(?:[^\.]+\.)?([^\.]{3,}\..+)\z~i', $referrer['host'], $parts) == 1) |
||
| 668 | $referrer['host'] = $parts[1]; |
||
| 669 | |||
| 670 | if (preg_match('~(?:[^\.]+\.)?([^\.]{3,}\..+)\z~i', $real_host, $parts) == 1) |
||
| 671 | $real_host = $parts[1]; |
||
| 672 | } |
||
| 673 | |||
| 674 | // Okay: referrer must either match parsed_url or real_host. |
||
| 675 | if (isset($parsed_url['host']) && strtolower($referrer['host']) != strtolower($parsed_url['host']) && strtolower($referrer['host']) != strtolower($real_host)) |
||
| 676 | { |
||
| 677 | $error = 'verify_url_fail'; |
||
| 678 | $log_error = true; |
||
| 679 | } |
||
| 680 | } |
||
| 681 | |||
| 682 | // Well, first of all, if a from_action is specified you'd better have an old_url. |
||
| 683 | if (!empty($from_action) && (!isset($_SESSION['old_url']) || preg_match('~[?;&]action=' . $from_action . '([;&]|$)~', $_SESSION['old_url']) == 0)) |
||
| 684 | { |
||
| 685 | $error = 'verify_url_fail'; |
||
| 686 | $log_error = true; |
||
| 687 | } |
||
| 688 | |||
| 689 | if (strtolower($_SERVER['HTTP_USER_AGENT']) == 'hacker') |
||
| 690 | fatal_error('Sound the alarm! It\'s a hacker! Close the castle gates!!', false); |
||
| 691 | |||
| 692 | // Everything is ok, return an empty string. |
||
| 693 | if (!isset($error)) |
||
| 694 | return ''; |
||
| 695 | // A session error occurred, show the error. |
||
| 696 | elseif ($is_fatal) |
||
| 697 | { |
||
| 698 | if (isset($_GET['xml'])) |
||
| 699 | { |
||
| 700 | ob_end_clean(); |
||
| 701 | send_http_status(403, 'Forbidden - Session timeout'); |
||
| 702 | die; |
||
|
0 ignored issues
–
show
|
|||
| 703 | } |
||
| 704 | else |
||
| 705 | fatal_lang_error($error, isset($log_error) ? 'user' : false); |
||
| 706 | } |
||
| 707 | // A session error occurred, return the error to the calling function. |
||
| 708 | else |
||
| 709 | return $error; |
||
| 710 | |||
| 711 | // We really should never fall through here, for very important reasons. Let's make sure. |
||
| 712 | trigger_error('Hacking attempt...', E_USER_ERROR); |
||
| 713 | } |
||
| 714 | |||
| 715 | /** |
||
| 716 | * Check if a specific confirm parameter was given. |
||
| 717 | * |
||
| 718 | * @param string $action The action we want to check against |
||
| 719 | * @return bool|string True if the check passed or a token |
||
| 720 | */ |
||
| 721 | function checkConfirm($action) |
||
| 722 | { |
||
| 723 | global $modSettings, $smcFunc; |
||
| 724 | |||
| 725 | if (isset($_GET['confirm']) && isset($_SESSION['confirm_' . $action]) && md5($_GET['confirm'] . $_SERVER['HTTP_USER_AGENT']) == $_SESSION['confirm_' . $action]) |
||
| 726 | return true; |
||
| 727 | |||
| 728 | else |
||
| 729 | { |
||
| 730 | $token = md5($smcFunc['random_int']() . session_id() . (string) microtime() . $modSettings['rand_seed']); |
||
| 731 | $_SESSION['confirm_' . $action] = md5($token . $_SERVER['HTTP_USER_AGENT']); |
||
| 732 | |||
| 733 | return $token; |
||
| 734 | } |
||
| 735 | } |
||
| 736 | |||
| 737 | /** |
||
| 738 | * Lets give you a token of our appreciation. |
||
| 739 | * |
||
| 740 | * @param string $action The action to create the token for |
||
| 741 | * @param string $type The type of token ('post', 'get' or 'request') |
||
| 742 | * @return array An array containing the name of the token var and the actual token |
||
| 743 | */ |
||
| 744 | function createToken($action, $type = 'post') |
||
| 745 | { |
||
| 746 | global $modSettings, $context, $smcFunc; |
||
| 747 | |||
| 748 | $token = md5($smcFunc['random_int']() . session_id() . (string) microtime() . $modSettings['rand_seed'] . $type); |
||
| 749 | $token_var = substr(preg_replace('~^\d+~', '', md5($smcFunc['random_int']() . (string) microtime() . $smcFunc['random_int']())), 0, $smcFunc['random_int'](7, 12)); |
||
| 750 | |||
| 751 | $_SESSION['token'][$type . '-' . $action] = array($token_var, md5($token . $_SERVER['HTTP_USER_AGENT']), time(), $token); |
||
| 752 | |||
| 753 | $context[$action . '_token'] = $token; |
||
| 754 | $context[$action . '_token_var'] = $token_var; |
||
| 755 | |||
| 756 | return array($action . '_token_var' => $token_var, $action . '_token' => $token); |
||
| 757 | } |
||
| 758 | |||
| 759 | /** |
||
| 760 | * Only patrons with valid tokens can ride this ride. |
||
| 761 | * |
||
| 762 | * @param string $action The action to validate the token for |
||
| 763 | * @param string $type The type of request (get, request, or post) |
||
| 764 | * @param bool $reset Whether to reset the token and display an error if validation fails |
||
| 765 | * @return bool|string If the action is login, returns the token for the action, otherwise returns whether the validation was successful |
||
| 766 | */ |
||
| 767 | function validateToken($action, $type = 'post', $reset = true) |
||
| 768 | { |
||
| 769 | $type = $type == 'get' || $type == 'request' ? $type : 'post'; |
||
| 770 | |||
| 771 | // Logins are special: the token is used to has the password with javascript before POST it |
||
| 772 | if ($action == 'login') |
||
| 773 | { |
||
| 774 | if (isset($_SESSION['token'][$type . '-' . $action])) |
||
| 775 | { |
||
| 776 | $return = $_SESSION['token'][$type . '-' . $action][3]; |
||
| 777 | unset($_SESSION['token'][$type . '-' . $action]); |
||
| 778 | return $return; |
||
| 779 | } |
||
| 780 | else |
||
| 781 | return ''; |
||
| 782 | } |
||
| 783 | |||
| 784 | // This nasty piece of code validates a token. |
||
| 785 | /* |
||
| 786 | 1. The token exists in session. |
||
| 787 | 2. The {$type} variable should exist. |
||
| 788 | 3. We concat the variable we received with the user agent |
||
| 789 | 4. Match that result against what is in the session. |
||
| 790 | 5. If it matches, success, otherwise we fallout. |
||
| 791 | */ |
||
| 792 | if (isset($_SESSION['token'][$type . '-' . $action], $GLOBALS['_' . strtoupper($type)][$_SESSION['token'][$type . '-' . $action][0]]) && md5($GLOBALS['_' . strtoupper($type)][$_SESSION['token'][$type . '-' . $action][0]] . $_SERVER['HTTP_USER_AGENT']) == $_SESSION['token'][$type . '-' . $action][1]) |
||
| 793 | { |
||
| 794 | // Invalidate this token now. |
||
| 795 | unset($_SESSION['token'][$type . '-' . $action]); |
||
| 796 | |||
| 797 | return true; |
||
| 798 | } |
||
| 799 | |||
| 800 | // Patrons with invalid tokens get the boot. |
||
| 801 | if ($reset) |
||
| 802 | { |
||
| 803 | // Might as well do some cleanup on this. |
||
| 804 | cleanTokens(); |
||
| 805 | |||
| 806 | // I'm back baby. |
||
| 807 | createToken($action, $type); |
||
| 808 | |||
| 809 | fatal_lang_error('token_verify_fail', false); |
||
| 810 | } |
||
| 811 | // Remove this token as its useless |
||
| 812 | else |
||
| 813 | unset($_SESSION['token'][$type . '-' . $action]); |
||
| 814 | |||
| 815 | // Randomly check if we should remove some older tokens. |
||
| 816 | if (mt_rand(0, 138) == 23) |
||
| 817 | cleanTokens(); |
||
| 818 | |||
| 819 | return false; |
||
| 820 | } |
||
| 821 | |||
| 822 | /** |
||
| 823 | * Removes old unused tokens from session |
||
| 824 | * defaults to 3 hours before a token is considered expired |
||
| 825 | * if $complete = true will remove all tokens |
||
| 826 | * |
||
| 827 | * @param bool $complete Whether to remove all tokens or only expired ones |
||
| 828 | */ |
||
| 829 | function cleanTokens($complete = false) |
||
| 830 | { |
||
| 831 | // We appreciate cleaning up after yourselves. |
||
| 832 | if (!isset($_SESSION['token'])) |
||
| 833 | return; |
||
| 834 | |||
| 835 | // Clean up tokens, trying to give enough time still. |
||
| 836 | foreach ($_SESSION['token'] as $key => $data) |
||
| 837 | if ($data[2] + 10800 < time() || $complete) |
||
| 838 | unset($_SESSION['token'][$key]); |
||
| 839 | } |
||
| 840 | |||
| 841 | /** |
||
| 842 | * Check whether a form has been submitted twice. |
||
| 843 | * Registers a sequence number for a form. |
||
| 844 | * Checks whether a submitted sequence number is registered in the current session. |
||
| 845 | * Depending on the value of is_fatal shows an error or returns true or false. |
||
| 846 | * Frees a sequence number from the stack after it's been checked. |
||
| 847 | * Frees a sequence number without checking if action == 'free'. |
||
| 848 | * |
||
| 849 | * @param string $action The action - can be 'register', 'check' or 'free' |
||
| 850 | * @param bool $is_fatal Whether to die with a fatal error |
||
| 851 | * @return void|bool If the action isn't check, returns nothing, otherwise returns whether the check was successful |
||
| 852 | */ |
||
| 853 | function checkSubmitOnce($action, $is_fatal = true) |
||
| 854 | { |
||
| 855 | global $context; |
||
| 856 | |||
| 857 | if (!isset($_SESSION['forms'])) |
||
| 858 | $_SESSION['forms'] = array(); |
||
| 859 | |||
| 860 | // Register a form number and store it in the session stack. (use this on the page that has the form.) |
||
| 861 | if ($action == 'register') |
||
| 862 | { |
||
| 863 | $context['form_sequence_number'] = 0; |
||
| 864 | while (empty($context['form_sequence_number']) || in_array($context['form_sequence_number'], $_SESSION['forms'])) |
||
| 865 | $context['form_sequence_number'] = mt_rand(1, 16000000); |
||
| 866 | } |
||
| 867 | // Check whether the submitted number can be found in the session. |
||
| 868 | elseif ($action == 'check') |
||
| 869 | { |
||
| 870 | if (!isset($_REQUEST['seqnum'])) |
||
| 871 | return true; |
||
| 872 | elseif (!in_array($_REQUEST['seqnum'], $_SESSION['forms'])) |
||
| 873 | { |
||
| 874 | $_SESSION['forms'][] = (int) $_REQUEST['seqnum']; |
||
| 875 | return true; |
||
| 876 | } |
||
| 877 | elseif ($is_fatal) |
||
| 878 | fatal_lang_error('error_form_already_submitted', false); |
||
| 879 | else |
||
| 880 | return false; |
||
| 881 | } |
||
| 882 | // Don't check, just free the stack number. |
||
| 883 | elseif ($action == 'free' && isset($_REQUEST['seqnum']) && in_array($_REQUEST['seqnum'], $_SESSION['forms'])) |
||
| 884 | $_SESSION['forms'] = array_diff($_SESSION['forms'], array($_REQUEST['seqnum'])); |
||
| 885 | elseif ($action != 'free') |
||
| 886 | trigger_error('checkSubmitOnce(): Invalid action \'' . $action . '\'', E_USER_WARNING); |
||
| 887 | } |
||
| 888 | |||
| 889 | /** |
||
| 890 | * Check the user's permissions. |
||
| 891 | * checks whether the user is allowed to do permission. (ie. post_new.) |
||
| 892 | * If boards is specified, checks those boards instead of the current one. |
||
| 893 | * If any is true, will return true if the user has the permission on any of the specified boards |
||
| 894 | * Always returns true if the user is an administrator. |
||
| 895 | * |
||
| 896 | * @param string|array $permission A single permission to check or an array of permissions to check |
||
| 897 | * @param int|array $boards The ID of a board or an array of board IDs if we want to check board-level permissions |
||
| 898 | * @param bool $any Whether to check for permission on at least one board instead of all boards |
||
| 899 | * @return bool Whether the user has the specified permission |
||
| 900 | */ |
||
| 901 | function allowedTo($permission, $boards = null, $any = false) |
||
| 902 | { |
||
| 903 | global $user_info, $smcFunc; |
||
| 904 | static $perm_cache = array(); |
||
| 905 | |||
| 906 | // You're always allowed to do nothing. (unless you're a working man, MR. LAZY :P!) |
||
| 907 | if (empty($permission)) |
||
| 908 | return true; |
||
| 909 | |||
| 910 | // You're never allowed to do something if your data hasn't been loaded yet! |
||
| 911 | if (empty($user_info) || !isset($user_info['permissions'])) |
||
| 912 | return false; |
||
| 913 | |||
| 914 | // Administrators are supermen :P. |
||
| 915 | if ($user_info['is_admin']) |
||
| 916 | return true; |
||
| 917 | |||
| 918 | // Let's ensure this is an array. |
||
| 919 | $permission = (array) $permission; |
||
| 920 | |||
| 921 | // Are we checking the _current_ board, or some other boards? |
||
| 922 | if ($boards === null) |
||
| 923 | { |
||
| 924 | if (count(array_intersect($permission, $user_info['permissions'])) != 0) |
||
| 925 | return true; |
||
| 926 | // You aren't allowed, by default. |
||
| 927 | else |
||
| 928 | return false; |
||
| 929 | } |
||
| 930 | elseif (!is_array($boards)) |
||
| 931 | $boards = array($boards); |
||
| 932 | |||
| 933 | $cache_key = hash('md5', $user_info['id'] . '-' . implode(',', $permission) . '-' . implode(',', $boards) . '-' . $any); |
||
| 934 | |||
| 935 | if (isset($perm_cache[$cache_key])) |
||
| 936 | return $perm_cache[$cache_key]; |
||
| 937 | |||
| 938 | $request = $smcFunc['db_query']('', ' |
||
| 939 | SELECT MIN(bp.add_deny) AS add_deny |
||
| 940 | FROM {db_prefix}boards AS b |
||
| 941 | INNER JOIN {db_prefix}board_permissions AS bp ON (bp.id_profile = b.id_profile) |
||
| 942 | LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = b.id_board AND mods.id_member = {int:current_member}) |
||
| 943 | LEFT JOIN {db_prefix}moderator_groups AS modgs ON (modgs.id_board = b.id_board AND modgs.id_group IN ({array_int:group_list})) |
||
| 944 | WHERE b.id_board IN ({array_int:board_list}) |
||
| 945 | AND bp.id_group IN ({array_int:group_list}, {int:moderator_group}) |
||
| 946 | AND bp.permission IN ({array_string:permission_list}) |
||
| 947 | AND (mods.id_member IS NOT NULL OR modgs.id_group IS NOT NULL OR bp.id_group != {int:moderator_group}) |
||
| 948 | GROUP BY b.id_board', |
||
| 949 | array( |
||
| 950 | 'current_member' => $user_info['id'], |
||
| 951 | 'board_list' => $boards, |
||
| 952 | 'group_list' => $user_info['groups'], |
||
| 953 | 'moderator_group' => 3, |
||
| 954 | 'permission_list' => $permission, |
||
| 955 | ) |
||
| 956 | ); |
||
| 957 | |||
| 958 | if ($any) |
||
| 959 | { |
||
| 960 | $result = false; |
||
| 961 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 962 | { |
||
| 963 | $result = !empty($row['add_deny']); |
||
| 964 | if ($result == true) |
||
| 965 | break; |
||
| 966 | } |
||
| 967 | $smcFunc['db_free_result']($request); |
||
| 968 | $return = $result; |
||
| 969 | } |
||
| 970 | |||
| 971 | // Make sure they can do it on all of the boards. |
||
| 972 | elseif ($smcFunc['db_num_rows']($request) != count($boards)) |
||
| 973 | $return = false; |
||
| 974 | |||
| 975 | else |
||
| 976 | { |
||
| 977 | $result = true; |
||
| 978 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 979 | $result &= !empty($row['add_deny']); |
||
| 980 | $smcFunc['db_free_result']($request); |
||
| 981 | $return = $result; |
||
| 982 | } |
||
| 983 | |||
| 984 | $perm_cache[$cache_key] = $return; |
||
| 985 | |||
| 986 | // If the query returned 1, they can do it... otherwise, they can't. |
||
| 987 | return $return; |
||
| 988 | } |
||
| 989 | |||
| 990 | /** |
||
| 991 | * Fatal error if they cannot. |
||
| 992 | * Uses allowedTo() to check if the user is allowed to do permission. |
||
| 993 | * Checks the passed boards or current board for the permission. |
||
| 994 | * If $any is true, the user only needs permission on at least one of the boards to pass |
||
| 995 | * If they are not, it loads the Errors language file and shows an error using $txt['cannot_' . $permission]. |
||
| 996 | * If they are a guest and cannot do it, this calls is_not_guest(). |
||
| 997 | * |
||
| 998 | * @param string|array $permission A single permission to check or an array of permissions to check |
||
| 999 | * @param int|array $boards The ID of a single board or an array of board IDs if we're checking board-level permissions (null otherwise) |
||
| 1000 | * @param bool $any Whether to check for permission on at least one board instead of all boards |
||
| 1001 | */ |
||
| 1002 | function isAllowedTo($permission, $boards = null, $any = false) |
||
| 1003 | { |
||
| 1004 | global $user_info, $txt; |
||
| 1005 | |||
| 1006 | $heavy_permissions = array( |
||
| 1007 | 'admin_forum', |
||
| 1008 | 'manage_attachments', |
||
| 1009 | 'manage_smileys', |
||
| 1010 | 'manage_boards', |
||
| 1011 | 'edit_news', |
||
| 1012 | 'moderate_forum', |
||
| 1013 | 'manage_bans', |
||
| 1014 | 'manage_membergroups', |
||
| 1015 | 'manage_permissions', |
||
| 1016 | ); |
||
| 1017 | |||
| 1018 | // Make it an array, even if a string was passed. |
||
| 1019 | $permission = (array) $permission; |
||
| 1020 | |||
| 1021 | call_integration_hook('integrate_heavy_permissions_session', array(&$heavy_permissions)); |
||
| 1022 | |||
| 1023 | // Check the permission and return an error... |
||
| 1024 | if (!allowedTo($permission, $boards, $any)) |
||
| 1025 | { |
||
| 1026 | // Pick the last array entry as the permission shown as the error. |
||
| 1027 | $error_permission = array_shift($permission); |
||
| 1028 | |||
| 1029 | // If they are a guest, show a login. (because the error might be gone if they do!) |
||
| 1030 | if ($user_info['is_guest']) |
||
| 1031 | { |
||
| 1032 | loadLanguage('Errors'); |
||
| 1033 | is_not_guest($txt['cannot_' . $error_permission]); |
||
| 1034 | } |
||
| 1035 | |||
| 1036 | // Clear the action because they aren't really doing that! |
||
| 1037 | $_GET['action'] = ''; |
||
| 1038 | $_GET['board'] = ''; |
||
| 1039 | $_GET['topic'] = ''; |
||
| 1040 | writeLog(true); |
||
| 1041 | |||
| 1042 | fatal_lang_error('cannot_' . $error_permission, false); |
||
| 1043 | |||
| 1044 | // Getting this far is a really big problem, but let's try our best to prevent any cases... |
||
| 1045 | trigger_error('Hacking attempt...', E_USER_ERROR); |
||
| 1046 | } |
||
| 1047 | |||
| 1048 | // If you're doing something on behalf of some "heavy" permissions, validate your session. |
||
| 1049 | // (take out the heavy permissions, and if you can't do anything but those, you need a validated session.) |
||
| 1050 | if (!allowedTo(array_diff($permission, $heavy_permissions), $boards)) |
||
| 1051 | validateSession(); |
||
| 1052 | } |
||
| 1053 | |||
| 1054 | /** |
||
| 1055 | * Return the boards a user has a certain (board) permission on. (array(0) if all.) |
||
| 1056 | * - returns a list of boards on which the user is allowed to do the specified permission. |
||
| 1057 | * - returns an array with only a 0 in it if the user has permission to do this on every board. |
||
| 1058 | * - returns an empty array if he or she cannot do this on any board. |
||
| 1059 | * If check_access is true will also make sure the group has proper access to that board. |
||
| 1060 | * |
||
| 1061 | * @param string|array $permissions A single permission to check or an array of permissions to check |
||
| 1062 | * @param bool $check_access Whether to check only the boards the user has access to |
||
| 1063 | * @param bool $simple Whether to return a simple array of board IDs or one with permissions as the keys |
||
| 1064 | * @return array An array of board IDs or an array containing 'permission' => 'board,board2,...' pairs |
||
| 1065 | */ |
||
| 1066 | function boardsAllowedTo($permissions, $check_access = true, $simple = true) |
||
| 1067 | { |
||
| 1068 | global $user_info, $smcFunc; |
||
| 1069 | |||
| 1070 | // Arrays are nice, most of the time. |
||
| 1071 | $permissions = (array) $permissions; |
||
| 1072 | |||
| 1073 | /* |
||
| 1074 | * Set $simple to true to use this function as it were in SMF 2.0.x. |
||
| 1075 | * Otherwise, the resultant array becomes split into the multiple |
||
| 1076 | * permissions that were passed. Other than that, it's just the normal |
||
| 1077 | * state of play that you're used to. |
||
| 1078 | */ |
||
| 1079 | |||
| 1080 | // Administrators are all powerful, sorry. |
||
| 1081 | if ($user_info['is_admin']) |
||
| 1082 | { |
||
| 1083 | if ($simple) |
||
| 1084 | return array(0); |
||
| 1085 | else |
||
| 1086 | { |
||
| 1087 | $boards = array(); |
||
| 1088 | foreach ($permissions as $permission) |
||
| 1089 | $boards[$permission] = array(0); |
||
| 1090 | |||
| 1091 | return $boards; |
||
| 1092 | } |
||
| 1093 | } |
||
| 1094 | |||
| 1095 | // All groups the user is in except 'moderator'. |
||
| 1096 | $groups = array_diff($user_info['groups'], array(3)); |
||
| 1097 | |||
| 1098 | $request = $smcFunc['db_query']('', ' |
||
| 1099 | SELECT b.id_board, bp.add_deny' . ($simple ? '' : ', bp.permission') . ' |
||
| 1100 | FROM {db_prefix}board_permissions AS bp |
||
| 1101 | INNER JOIN {db_prefix}boards AS b ON (b.id_profile = bp.id_profile) |
||
| 1102 | LEFT JOIN {db_prefix}moderators AS mods ON (mods.id_board = b.id_board AND mods.id_member = {int:current_member}) |
||
| 1103 | LEFT JOIN {db_prefix}moderator_groups AS modgs ON (modgs.id_board = b.id_board AND modgs.id_group IN ({array_int:group_list})) |
||
| 1104 | WHERE bp.id_group IN ({array_int:group_list}, {int:moderator_group}) |
||
| 1105 | AND bp.permission IN ({array_string:permissions}) |
||
| 1106 | AND (mods.id_member IS NOT NULL OR modgs.id_group IS NOT NULL OR bp.id_group != {int:moderator_group})' . |
||
| 1107 | ($check_access ? ' AND {query_see_board}' : ''), |
||
| 1108 | array( |
||
| 1109 | 'current_member' => $user_info['id'], |
||
| 1110 | 'group_list' => $groups, |
||
| 1111 | 'moderator_group' => 3, |
||
| 1112 | 'permissions' => $permissions, |
||
| 1113 | ) |
||
| 1114 | ); |
||
| 1115 | $boards = array(); |
||
| 1116 | $deny_boards = array(); |
||
| 1117 | while ($row = $smcFunc['db_fetch_assoc']($request)) |
||
| 1118 | { |
||
| 1119 | if ($simple) |
||
| 1120 | { |
||
| 1121 | if (empty($row['add_deny'])) |
||
| 1122 | $deny_boards[] = $row['id_board']; |
||
| 1123 | else |
||
| 1124 | $boards[] = $row['id_board']; |
||
| 1125 | } |
||
| 1126 | else |
||
| 1127 | { |
||
| 1128 | if (empty($row['add_deny'])) |
||
| 1129 | $deny_boards[$row['permission']][] = $row['id_board']; |
||
| 1130 | else |
||
| 1131 | $boards[$row['permission']][] = $row['id_board']; |
||
| 1132 | } |
||
| 1133 | } |
||
| 1134 | $smcFunc['db_free_result']($request); |
||
| 1135 | |||
| 1136 | if ($simple) |
||
| 1137 | $boards = array_unique(array_values(array_diff($boards, $deny_boards))); |
||
| 1138 | else |
||
| 1139 | { |
||
| 1140 | foreach ($permissions as $permission) |
||
| 1141 | { |
||
| 1142 | // never had it to start with |
||
| 1143 | if (empty($boards[$permission])) |
||
| 1144 | $boards[$permission] = array(); |
||
| 1145 | else |
||
| 1146 | { |
||
| 1147 | // Or it may have been removed |
||
| 1148 | $deny_boards[$permission] = isset($deny_boards[$permission]) ? $deny_boards[$permission] : array(); |
||
| 1149 | $boards[$permission] = array_unique(array_values(array_diff($boards[$permission], $deny_boards[$permission]))); |
||
| 1150 | } |
||
| 1151 | } |
||
| 1152 | } |
||
| 1153 | |||
| 1154 | return $boards; |
||
| 1155 | } |
||
| 1156 | |||
| 1157 | /** |
||
| 1158 | * This function attempts to protect from spammed messages and the like. |
||
| 1159 | * The time taken depends on error_type - generally uses the modSetting. |
||
| 1160 | * |
||
| 1161 | * @param string $error_type The error type. Also used as a $txt index (not an actual string). |
||
| 1162 | * @param boolean $only_return_result Whether you want the function to die with a fatal_lang_error. |
||
| 1163 | * @return bool Whether they've posted within the limit |
||
| 1164 | */ |
||
| 1165 | function spamProtection($error_type, $only_return_result = false) |
||
| 1166 | { |
||
| 1167 | global $modSettings, $user_info, $smcFunc; |
||
| 1168 | |||
| 1169 | // Certain types take less/more time. |
||
| 1170 | $timeOverrides = array( |
||
| 1171 | 'login' => 2, |
||
| 1172 | 'register' => 2, |
||
| 1173 | 'remind' => 30, |
||
| 1174 | 'sendmail' => $modSettings['spamWaitTime'] * 5, |
||
| 1175 | 'reporttm' => $modSettings['spamWaitTime'] * 4, |
||
| 1176 | 'search' => !empty($modSettings['search_floodcontrol_time']) ? $modSettings['search_floodcontrol_time'] : 1, |
||
| 1177 | ); |
||
| 1178 | |||
| 1179 | call_integration_hook('integrate_spam_protection', array(&$timeOverrides)); |
||
| 1180 | |||
| 1181 | // Moderators are free... |
||
| 1182 | if (!allowedTo('moderate_board')) |
||
| 1183 | $timeLimit = isset($timeOverrides[$error_type]) ? $timeOverrides[$error_type] : $modSettings['spamWaitTime']; |
||
| 1184 | else |
||
| 1185 | $timeLimit = 2; |
||
| 1186 | |||
| 1187 | // Delete old entries... |
||
| 1188 | $smcFunc['db_query']('', ' |
||
| 1189 | DELETE FROM {db_prefix}log_floodcontrol |
||
| 1190 | WHERE log_time < {int:log_time} |
||
| 1191 | AND log_type = {string:log_type}', |
||
| 1192 | array( |
||
| 1193 | 'log_time' => time() - $timeLimit, |
||
| 1194 | 'log_type' => $error_type, |
||
| 1195 | ) |
||
| 1196 | ); |
||
| 1197 | |||
| 1198 | // Add a new entry, deleting the old if necessary. |
||
| 1199 | $smcFunc['db_insert']('replace', |
||
| 1200 | '{db_prefix}log_floodcontrol', |
||
| 1201 | array('ip' => 'inet', 'log_time' => 'int', 'log_type' => 'string'), |
||
| 1202 | array($user_info['ip'], time(), $error_type), |
||
| 1203 | array('ip', 'log_type') |
||
| 1204 | ); |
||
| 1205 | |||
| 1206 | // If affected is 0 or 2, it was there already. |
||
| 1207 | if ($smcFunc['db_affected_rows']() != 1) |
||
| 1208 | { |
||
| 1209 | // Spammer! You only have to wait a *few* seconds! |
||
| 1210 | if (!$only_return_result) |
||
| 1211 | fatal_lang_error($error_type . '_WaitTime_broken', false, array($timeLimit)); |
||
| 1212 | |||
| 1213 | return true; |
||
| 1214 | } |
||
| 1215 | |||
| 1216 | // They haven't posted within the limit. |
||
| 1217 | return false; |
||
| 1218 | } |
||
| 1219 | |||
| 1220 | /** |
||
| 1221 | * A generic function to create a pair of index.php and .htaccess files in a directory |
||
| 1222 | * |
||
| 1223 | * @param string|array $paths The (absolute) directory path |
||
| 1224 | * @param boolean $attachments Whether this is an attachment directory |
||
| 1225 | * @return bool|array True on success an array of errors if anything fails |
||
| 1226 | */ |
||
| 1227 | function secureDirectory($paths, $attachments = false) |
||
| 1228 | { |
||
| 1229 | $errors = array(); |
||
| 1230 | |||
| 1231 | // Work with arrays |
||
| 1232 | $paths = (array) $paths; |
||
| 1233 | |||
| 1234 | if (empty($path)) |
||
| 1235 | $errors[] = 'empty_path'; |
||
| 1236 | |||
| 1237 | if (!empty($errors)) |
||
| 1238 | return $errors; |
||
| 1239 | |||
| 1240 | foreach ($paths as $path) |
||
| 1241 | { |
||
| 1242 | if (!is_writable($path)) |
||
| 1243 | { |
||
| 1244 | $errors[] = 'path_not_writable'; |
||
| 1245 | |||
| 1246 | continue; |
||
| 1247 | } |
||
| 1248 | |||
| 1249 | $directory_name = basename($path); |
||
| 1250 | |||
| 1251 | $close = empty($attachments) ? ' |
||
| 1252 | </Files>' : ' |
||
| 1253 | Allow from localhost |
||
| 1254 | </Files> |
||
| 1255 | |||
| 1256 | RemoveHandler .php .php3 .phtml .cgi .fcgi .pl .fpl .shtml'; |
||
| 1257 | |||
| 1258 | if (file_exists($path . '/.htaccess')) |
||
| 1259 | { |
||
| 1260 | $errors[] = 'htaccess_exists'; |
||
| 1261 | |||
| 1262 | continue; |
||
| 1263 | } |
||
| 1264 | |||
| 1265 | else |
||
| 1266 | { |
||
| 1267 | $fh = @fopen($path . '/.htaccess', 'w'); |
||
| 1268 | |||
| 1269 | if ($fh) |
||
| 1270 | { |
||
| 1271 | fwrite($fh, '<Files *> |
||
| 1272 | Order Deny,Allow |
||
| 1273 | Deny from all' . $close); |
||
| 1274 | fclose($fh); |
||
| 1275 | } |
||
| 1276 | |||
| 1277 | else |
||
| 1278 | $errors[] = 'htaccess_cannot_create_file'; |
||
| 1279 | } |
||
| 1280 | |||
| 1281 | if (file_exists($path . '/index.php')) |
||
| 1282 | { |
||
| 1283 | $errors[] = 'index-php_exists'; |
||
| 1284 | |||
| 1285 | continue; |
||
| 1286 | } |
||
| 1287 | |||
| 1288 | else |
||
| 1289 | { |
||
| 1290 | $fh = @fopen($path . '/index.php', 'w'); |
||
| 1291 | |||
| 1292 | if ($fh) |
||
| 1293 | { |
||
| 1294 | fwrite($fh, '<' . '?php |
||
| 1295 | |||
| 1296 | /** |
||
| 1297 | * This file is here solely to protect your ' . $directory_name . ' directory. |
||
| 1298 | */ |
||
| 1299 | |||
| 1300 | // Look for Settings.php.... |
||
| 1301 | if (file_exists(dirname(dirname(__FILE__)) . \'/Settings.php\')) |
||
| 1302 | { |
||
| 1303 | // Found it! |
||
| 1304 | require(dirname(dirname(__FILE__)) . \'/Settings.php\'); |
||
| 1305 | header(\'location: \' . $boardurl); |
||
| 1306 | } |
||
| 1307 | // Can\'t find it... just forget it. |
||
| 1308 | else |
||
| 1309 | exit; |
||
| 1310 | |||
| 1311 | ?' . '>'); |
||
| 1312 | fclose($fh); |
||
| 1313 | } |
||
| 1314 | |||
| 1315 | else |
||
| 1316 | $errors[] = 'index-php_cannot_create_file'; |
||
| 1317 | } |
||
| 1318 | } |
||
| 1319 | |||
| 1320 | if (!empty($errors)) |
||
| 1321 | return $errors; |
||
| 1322 | |||
| 1323 | else |
||
| 1324 | return true; |
||
| 1325 | } |
||
| 1326 | |||
| 1327 | /** |
||
| 1328 | * This sets the X-Frame-Options header. |
||
| 1329 | * |
||
| 1330 | * @param string $override An option to override (either 'SAMEORIGIN' or 'DENY') |
||
| 1331 | * @since 2.1 |
||
| 1332 | */ |
||
| 1333 | function frameOptionsHeader($override = null) |
||
| 1334 | { |
||
| 1335 | global $modSettings; |
||
| 1336 | |||
| 1337 | $option = 'SAMEORIGIN'; |
||
| 1338 | if (is_null($override) && !empty($modSettings['frame_security'])) |
||
| 1339 | $option = $modSettings['frame_security']; |
||
| 1340 | elseif (in_array($override, array('SAMEORIGIN', 'DENY'))) |
||
| 1341 | $option = $override; |
||
| 1342 | |||
| 1343 | // Don't bother setting the header if we have disabled it. |
||
| 1344 | if ($option == 'DISABLE') |
||
| 1345 | return; |
||
| 1346 | |||
| 1347 | // Finally set it. |
||
| 1348 | header('x-frame-options: ' . $option); |
||
| 1349 | |||
| 1350 | // And some other useful ones. |
||
| 1351 | header('x-xss-protection: 1'); |
||
| 1352 | header('x-content-type-options: nosniff'); |
||
| 1353 | } |
||
| 1354 | |||
| 1355 | ?> |
In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.