1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/** |
4
|
|
|
* Initialize the ElkArte environment. |
5
|
|
|
* |
6
|
|
|
* @name ElkArte Forum |
7
|
|
|
* @copyright ElkArte Forum contributors |
8
|
|
|
* @license BSD http://opensource.org/licenses/BSD-3-Clause |
9
|
|
|
* |
10
|
|
|
* This file contains code covered by: |
11
|
|
|
* copyright: 2011 Simple Machines (http://www.simplemachines.org) |
12
|
|
|
* license: BSD, See included LICENSE.TXT for terms and conditions. |
13
|
|
|
* |
14
|
|
|
* @version 1.1.1 |
15
|
|
|
* |
16
|
|
|
*/ |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* Class Bootstrap |
20
|
|
|
* |
21
|
|
|
* This takes care of the initial loading and feeding of Elkarte from |
22
|
|
|
* either SSI or Index |
23
|
|
|
*/ |
24
|
|
|
class Bootstrap |
25
|
|
|
{ |
26
|
|
|
/** |
27
|
|
|
* Bootstrap constructor. |
28
|
|
|
* |
29
|
|
|
* @param bool $standalone |
30
|
|
|
* - true to boot outside of elkarte |
31
|
|
|
* - false to bootstrap the main elkarte site. |
32
|
|
|
* @throws \Elk_Exception |
33
|
|
|
*/ |
34
|
|
|
public function __construct($standalone = true) |
35
|
|
|
{ |
36
|
|
|
// Bootstrap only once. |
37
|
|
|
if (!defined('ELKBOOT')) |
38
|
|
|
{ |
39
|
|
|
// We're going to set a few globals |
40
|
|
|
global $time_start, $ssi_error_reporting, $db_show_debug; |
41
|
|
|
|
42
|
|
|
// Your on the clock |
43
|
|
|
$time_start = microtime(true); |
44
|
|
|
|
45
|
|
|
// Unless settings.php tells us otherwise |
46
|
|
|
$db_show_debug = false; |
47
|
|
|
|
48
|
|
|
// Report errors but not depreciated ones |
49
|
|
|
$ssi_error_reporting = error_reporting(E_ALL & ~E_DEPRECATED); |
50
|
|
|
|
51
|
|
|
// Get the things needed for ALL modes |
52
|
|
|
$this->bringUpBasics(); |
53
|
|
|
|
54
|
|
|
// Going to run from the side entrance and not directly from inside elkarte |
55
|
|
|
if ($standalone) |
56
|
|
|
{ |
57
|
|
|
$this->ssi_main(); |
58
|
|
|
} |
59
|
|
|
} |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Calls the various initialization functions in the needed order |
64
|
|
|
*/ |
65
|
|
|
public function bringUpBasics() |
66
|
|
|
{ |
67
|
|
|
$this->setConstants(); |
68
|
|
|
$this->setRusage(); |
69
|
|
|
$this->clearGlobals(); |
70
|
|
|
$this->loadSettingsFile(); |
71
|
|
|
$this->validatePaths(); |
72
|
|
|
$this->loadDependants(); |
73
|
|
|
$this->loadAutoloader(); |
74
|
|
|
$this->checkMaintance(); |
75
|
|
|
$this->setDebug(); |
76
|
|
|
$this->bringUp(); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* Set the core constants, you know the ones we often forget to |
81
|
|
|
* update on new releases. |
82
|
|
|
*/ |
83
|
|
|
private function setConstants() |
84
|
|
|
{ |
85
|
|
|
// First things first, but not necessarily in that order. |
86
|
|
|
if (!defined('ELK')) |
87
|
|
|
{ |
88
|
|
|
define('ELK', '1'); |
89
|
|
|
} |
90
|
|
|
define('ELKBOOT', '1'); |
91
|
|
|
|
92
|
|
|
// The software version |
93
|
|
|
define('FORUM_VERSION', 'ElkArte 1.1.1'); |
94
|
|
|
|
95
|
|
|
// Shortcut for the browser cache stale |
96
|
|
|
define('CACHE_STALE', '?R111'); |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
/** |
100
|
|
|
* Get initial resource usage |
101
|
|
|
*/ |
102
|
|
|
private function setRusage() |
103
|
|
|
{ |
104
|
|
|
global $rusage_start; |
105
|
|
|
|
106
|
|
|
// Directional only script time usage for display |
107
|
|
|
// getrusage is missing in php < 7 on Windows |
108
|
|
|
if (function_exists('getrusage')) |
109
|
|
|
{ |
110
|
|
|
$rusage_start = getrusage(); |
111
|
|
|
} |
112
|
|
|
else |
113
|
|
|
{ |
114
|
|
|
$rusage_start = array(); |
115
|
|
|
} |
116
|
|
|
} |
117
|
|
|
|
118
|
|
|
/** |
119
|
|
|
* If they glo, they need to be cleaned. |
120
|
|
|
*/ |
121
|
|
|
private function clearGlobals() |
122
|
|
|
{ |
123
|
|
|
// We don't need no globals. (a bug in "old" versions of PHP) |
124
|
|
|
foreach (array('db_character_set', 'cachedir') as $variable) |
125
|
|
|
{ |
126
|
|
|
if (isset($GLOBALS[$variable])) |
127
|
|
|
{ |
128
|
|
|
unset($GLOBALS[$variable], $GLOBALS[$variable]); |
129
|
|
|
} |
130
|
|
|
} |
131
|
|
|
} |
132
|
|
|
|
133
|
|
|
/** |
134
|
|
|
* Loads the settings values into the global space |
135
|
|
|
*/ |
136
|
|
|
private function loadSettingsFile() |
137
|
|
|
{ |
138
|
|
|
// All those wonderful things found in settings |
139
|
|
|
global $maintenance, $mtitle, $msubject, $mmessage, $mbname, $language, $boardurl, $webmaster_email; |
140
|
|
|
global $cookiename, $db_type, $db_server, $db_port, $db_name, $db_user, $db_passwd; |
141
|
|
|
global $ssi_db_user, $ssi_db_passwd, $db_prefix, $db_persist, $db_error_send, $cache_accelerator; |
142
|
|
|
global $cache_uid, $cache_password, $cache_enable, $cache_memcached, $db_show_debug; |
143
|
|
|
global $cachedir, $boarddir, $sourcedir, $extdir, $languagedir, $ignore_install_dir; |
144
|
|
|
|
145
|
|
|
// Where the Settings.php file is located |
146
|
|
|
$settings_loc = __DIR__ . '/Settings.php'; |
147
|
|
|
|
148
|
|
|
// First thing: if the install dir exists, just send anybody there |
149
|
|
|
// The ignore_install_dir var is for developers only. Do not add it on production sites |
150
|
|
|
if (file_exists('install')) |
151
|
|
|
{ |
152
|
|
|
if (file_exists($settings_loc)) |
153
|
|
|
{ |
154
|
|
|
require_once($settings_loc); |
155
|
|
|
} |
156
|
|
|
|
157
|
|
|
if (empty($ignore_install_dir)) |
158
|
|
|
{ |
159
|
|
|
if (file_exists($settings_loc) && empty($_SESSION['installing'])) |
160
|
|
|
{ |
161
|
|
|
$redirec_file = 'upgrade.php'; |
162
|
|
|
} |
163
|
|
|
else |
164
|
|
|
{ |
165
|
|
|
$redirec_file = 'install.php'; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
header('Location: http' . (!empty($_SERVER['HTTPS']) && strtolower($_SERVER['HTTPS']) === 'on' ? 's' : '') . '://' . (empty($_SERVER['HTTP_HOST']) ? $_SERVER['SERVER_NAME'] . (empty($_SERVER['SERVER_PORT']) || $_SERVER['SERVER_PORT'] === '80' ? '' : ':' . $_SERVER['SERVER_PORT']) : $_SERVER['HTTP_HOST']) . (strtr(dirname($_SERVER['PHP_SELF']), '\\', '/') == '/' ? '' : strtr(dirname($_SERVER['PHP_SELF']), '\\', '/')) . '/install/' . $redirec_file); |
|
|
|
|
169
|
|
|
die(); |
|
|
|
|
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
else |
173
|
|
|
{ |
174
|
|
|
require_once($settings_loc); |
175
|
|
|
} |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Validate the paths set in Settings.php, correct as needed and move |
180
|
|
|
* them to constants. |
181
|
|
|
*/ |
182
|
|
|
private function validatePaths() |
183
|
|
|
{ |
184
|
|
|
global $boarddir, $sourcedir, $cachedir, $extdir, $languagedir; |
185
|
|
|
|
186
|
|
|
// Make sure the paths are correct... at least try to fix them. |
187
|
|
|
if (!file_exists($boarddir) && file_exists(__DIR__ . '/agreement.txt')) |
188
|
|
|
{ |
189
|
|
|
$boarddir = __DIR__; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
if (!file_exists($sourcedir . '/SiteDispatcher.class.php') && file_exists($boarddir . '/sources')) |
193
|
|
|
{ |
194
|
|
|
$sourcedir = $boarddir . '/sources'; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
// Check that directories which didn't exist in past releases are initialized. |
198
|
|
|
if ((empty($cachedir) || !file_exists($cachedir)) && file_exists($boarddir . '/cache')) |
199
|
|
|
{ |
200
|
|
|
$cachedir = $boarddir . '/cache'; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
if ((empty($extdir) || !file_exists($extdir)) && file_exists($sourcedir . '/ext')) |
204
|
|
|
{ |
205
|
|
|
$extdir = $sourcedir . '/ext'; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
if ((empty($languagedir) || !file_exists($languagedir)) && file_exists($boarddir . '/themes/default/languages')) |
209
|
|
|
{ |
210
|
|
|
$languagedir = $boarddir . '/themes/default/languages'; |
211
|
|
|
} |
212
|
|
|
|
213
|
|
|
// Time to forget about variables and go with constants! |
214
|
|
|
define('BOARDDIR', $boarddir); |
215
|
|
|
define('CACHEDIR', $cachedir); |
216
|
|
|
define('EXTDIR', $extdir); |
217
|
|
|
define('LANGUAGEDIR', $languagedir); |
218
|
|
|
define('SOURCEDIR', $sourcedir); |
219
|
|
|
define('ADMINDIR', $sourcedir . '/admin'); |
220
|
|
|
define('CONTROLLERDIR', $sourcedir . '/controllers'); |
221
|
|
|
define('SUBSDIR', $sourcedir . '/subs'); |
222
|
|
|
define('ADDONSDIR', $boarddir . '/addons'); |
223
|
|
|
unset($boarddir, $cachedir, $sourcedir, $languagedir, $extdir); |
224
|
|
|
} |
225
|
|
|
|
226
|
|
|
/** |
227
|
|
|
* We require access to several important files, so load them upfront |
228
|
|
|
*/ |
229
|
|
|
private function loadDependants() |
230
|
|
|
{ |
231
|
|
|
// Files we cannot live without. |
232
|
|
|
require_once(SOURCEDIR . '/QueryString.php'); |
233
|
|
|
require_once(SOURCEDIR . '/Session.php'); |
234
|
|
|
require_once(SOURCEDIR . '/Subs.php'); |
235
|
|
|
require_once(SOURCEDIR . '/Logging.php'); |
236
|
|
|
require_once(SOURCEDIR . '/Load.php'); |
237
|
|
|
require_once(SOURCEDIR . '/Security.php'); |
238
|
|
|
require_once(SUBSDIR . '/Cache.subs.php'); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
|
/** |
242
|
|
|
* The autoloader will take care most requests for files |
243
|
|
|
*/ |
244
|
|
|
private function loadAutoloader() |
245
|
|
|
{ |
246
|
|
|
// Initialize the class Autoloader |
247
|
|
|
require_once(SOURCEDIR . '/Autoloader.class.php'); |
248
|
|
|
$autoloader = Elk_Autoloader::instance(); |
249
|
|
|
$autoloader->setupAutoloader(array(SOURCEDIR, SUBSDIR, CONTROLLERDIR, ADMINDIR, ADDONSDIR)); |
250
|
|
|
$autoloader->register(SOURCEDIR, '\\ElkArte'); |
251
|
|
|
$autoloader->register(SOURCEDIR . '/subs/BBC', '\\BBC'); |
252
|
|
|
} |
253
|
|
|
|
254
|
|
|
/** |
255
|
|
|
* Check if we are in maintance mode, if so end here. |
256
|
|
|
*/ |
257
|
|
|
private function checkMaintance() |
258
|
|
|
{ |
259
|
|
|
global $maintenance, $ssi_maintenance_off; |
260
|
|
|
|
261
|
|
|
// Don't do john didley if the forum's been shut down completely. |
262
|
|
|
if (!empty($maintenance) && $maintenance == 2 && (!isset($ssi_maintenance_off) || $ssi_maintenance_off !== true)) |
263
|
|
|
{ |
264
|
|
|
Errors::instance()->display_maintenance_message(); |
265
|
|
|
} |
266
|
|
|
} |
267
|
|
|
|
268
|
|
|
/** |
269
|
|
|
* If you like lots of debug information in error messages and below the footer |
270
|
|
|
* then set $db_show_debug to true in settings. Don't do this on a production site. |
271
|
|
|
*/ |
272
|
|
|
private function setDebug() |
273
|
|
|
{ |
274
|
|
|
global $db_show_debug, $rusage_start; |
275
|
|
|
|
276
|
|
|
// Show lots of debug information below the page, not for production sites |
277
|
|
|
if ($db_show_debug === true) |
278
|
|
|
{ |
279
|
|
|
Debug::instance()->rusage('start', $rusage_start); |
280
|
|
|
} |
281
|
|
|
} |
282
|
|
|
|
283
|
|
|
/** |
284
|
|
|
* Time to see what has been requested, by whom and dispatch it to the proper handler |
285
|
|
|
*/ |
286
|
|
|
private function bringUp() |
287
|
|
|
{ |
288
|
|
|
global $context; |
289
|
|
|
|
290
|
|
|
// Clean the request. |
291
|
|
|
cleanRequest(); |
292
|
|
|
|
293
|
|
|
// Initiate the database connection and define some database functions to use. |
294
|
|
|
loadDatabase(); |
295
|
|
|
|
296
|
|
|
// Let's set up our shiny new hooks handler. |
297
|
|
|
Hooks::init(database(), Debug::instance()); |
298
|
|
|
|
299
|
|
|
// It's time for settings loaded from the database. |
300
|
|
|
reloadSettings(); |
301
|
|
|
|
302
|
|
|
// Our good ole' contextual array, which will hold everything |
303
|
|
|
if (empty($context)) |
304
|
|
|
{ |
305
|
|
|
$context = array(); |
306
|
|
|
} |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* If you are running SSI standalone, you need to call this function after bootstrap is |
311
|
|
|
* initialized. |
312
|
|
|
* |
313
|
|
|
* @throws \Elk_Exception |
314
|
|
|
*/ |
315
|
|
|
public function ssi_main() |
316
|
|
|
{ |
317
|
|
|
global $ssi_layers, $ssi_theme, $ssi_gzip, $ssi_ban, $ssi_guest_access; |
318
|
|
|
global $modSettings, $context, $sc, $board, $topic, $user_info, $txt; |
319
|
|
|
|
320
|
|
|
// Check on any hacking attempts. |
321
|
|
|
$this->_validRequestCheck(); |
322
|
|
|
|
323
|
|
|
// Gzip output? (because it must be boolean and true, this can't be hacked.) |
324
|
|
|
if (isset($ssi_gzip) && $ssi_gzip === true && detectServer()->outPutCompressionEnabled()) |
325
|
|
|
{ |
326
|
|
|
ob_start('ob_gzhandler'); |
327
|
|
|
} |
328
|
|
|
else |
329
|
|
|
{ |
330
|
|
|
$modSettings['enableCompressedOutput'] = '0'; |
331
|
|
|
} |
332
|
|
|
|
333
|
|
|
// Primarily, this is to fix the URLs... |
334
|
|
|
ob_start('ob_sessrewrite'); |
335
|
|
|
|
336
|
|
|
// Start the session... known to scramble SSI includes in cases... |
337
|
|
|
if (!headers_sent()) |
338
|
|
|
{ |
339
|
|
|
loadSession(); |
340
|
|
|
} |
341
|
|
|
else |
342
|
|
|
{ |
343
|
|
|
if (isset($_COOKIE[session_name()]) || isset($_REQUEST[session_name()])) |
344
|
|
|
{ |
345
|
|
|
// Make a stab at it, but ignore the E_WARNINGs generated because we can't send headers. |
346
|
|
|
$temp = error_reporting(error_reporting() & !E_WARNING); |
347
|
|
|
loadSession(); |
348
|
|
|
error_reporting($temp); |
349
|
|
|
} |
350
|
|
|
|
351
|
|
View Code Duplication |
if (!isset($_SESSION['session_value'])) |
352
|
|
|
{ |
353
|
|
|
$tokenizer = new Token_Hash(); |
354
|
|
|
$_SESSION['session_value'] = $tokenizer->generate_hash(32, session_id()); |
355
|
|
|
$_SESSION['session_var'] = substr(preg_replace('~^\d+~', '', $tokenizer->generate_hash(16, session_id())), 0, rand(7, 12)); |
356
|
|
|
} |
357
|
|
|
|
358
|
|
|
$sc = $_SESSION['session_value']; |
359
|
|
|
// This is here only to avoid session errors in PHP7 |
360
|
|
|
// microtime effectively forces the replacing of the session in the db each |
361
|
|
|
// time the page is loaded |
362
|
|
|
$_SESSION['mictrotime'] = microtime(); |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
// Get rid of $board and $topic... do stuff loadBoard would do. |
366
|
|
|
unset($board, $topic); |
367
|
|
|
$user_info['is_mod'] = false; |
368
|
|
|
$context['user']['is_mod'] = &$user_info['is_mod']; |
369
|
|
|
$context['linktree'] = array(); |
370
|
|
|
|
371
|
|
|
// Load the user and their cookie, as well as their settings. |
372
|
|
|
loadUserSettings(); |
373
|
|
|
|
374
|
|
|
// Load the current user's permissions.... |
375
|
|
|
loadPermissions(); |
376
|
|
|
|
377
|
|
|
// Load the current or SSI theme. (just use $ssi_theme = id_theme;) |
378
|
|
|
new ElkArte\Themes\ThemeLoader(isset($ssi_theme) ? (int) $ssi_theme : 0); |
379
|
|
|
|
380
|
|
|
// Load BadBehavior functions |
381
|
|
|
loadBadBehavior(); |
382
|
|
|
|
383
|
|
|
// @todo: probably not the best place, but somewhere it should be set... |
384
|
|
|
if (!headers_sent()) |
385
|
|
|
{ |
386
|
|
|
header('Content-Type: text/html; charset=UTF-8'); |
387
|
|
|
} |
388
|
|
|
|
389
|
|
|
// Take care of any banning that needs to be done. |
390
|
|
|
if (isset($_REQUEST['ssi_ban']) || (isset($ssi_ban) && $ssi_ban === true)) |
391
|
|
|
{ |
392
|
|
|
is_not_banned(); |
393
|
|
|
} |
394
|
|
|
|
395
|
|
|
// Do we allow guests in here? |
396
|
|
|
if (empty($ssi_guest_access) && empty($modSettings['allow_guestAccess']) && $user_info['is_guest'] && basename($_SERVER['PHP_SELF']) !== 'SSI.php') |
397
|
|
|
{ |
398
|
|
|
$controller = new Auth_Controller(new Event_manager()); |
399
|
|
|
$controller->action_kickguest(); |
400
|
|
|
obExit(null, true); |
401
|
|
|
} |
402
|
|
|
|
403
|
|
|
if (!empty($modSettings['front_page']) && is_callable(array($modSettings['front_page'], 'frontPageHook'))) |
404
|
|
|
{ |
405
|
|
|
$modSettings['default_forum_action'] = '?action=forum;'; |
406
|
|
|
} |
407
|
|
|
else |
408
|
|
|
{ |
409
|
|
|
$modSettings['default_forum_action'] = ''; |
410
|
|
|
} |
411
|
|
|
|
412
|
|
|
// Load the stuff like the menu bar, etc. |
413
|
|
|
if (isset($ssi_layers)) |
414
|
|
|
{ |
415
|
|
|
$template_layers = Template_Layers::instance(); |
416
|
|
|
$template_layers->removeAll(); |
417
|
|
|
foreach ($ssi_layers as $layer) |
418
|
|
|
{ |
419
|
|
|
$template_layers->addBegin($layer); |
420
|
|
|
} |
421
|
|
|
template_header(); |
422
|
|
|
} |
423
|
|
|
else |
424
|
|
|
{ |
425
|
|
|
setupThemeContext(); |
426
|
|
|
} |
427
|
|
|
|
428
|
|
|
// We need to set up user agent, and make more checks on the request |
429
|
|
|
$req = request(); |
430
|
|
|
|
431
|
|
|
// Make sure they didn't muss around with the settings... but only if it's not cli. |
432
|
|
|
if (isset($_SERVER['REMOTE_ADDR']) && session_id() === '') |
433
|
|
|
{ |
434
|
|
|
trigger_error($txt['ssi_session_broken'], E_USER_NOTICE); |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
// Without visiting the forum this session variable might not be set on submit. |
438
|
|
|
if (!isset($_SESSION['USER_AGENT']) && (!isset($_GET['ssi_function']) || $_GET['ssi_function'] !== 'pollVote')) |
439
|
|
|
{ |
440
|
|
|
$_SESSION['USER_AGENT'] = $req->user_agent(); |
441
|
|
|
} |
442
|
|
|
} |
443
|
|
|
|
444
|
|
|
/** |
445
|
|
|
* Used to ensure SSI requests are valid and not a probing attempt |
446
|
|
|
*/ |
447
|
|
|
private function _validRequestCheck() |
448
|
|
|
{ |
449
|
|
|
global $ssi_theme, $ssi_layers; |
450
|
|
|
|
451
|
|
|
// Check on any hacking attempts. |
452
|
|
|
if ( |
453
|
|
|
isset($_REQUEST['GLOBALS']) || isset($_COOKIE['GLOBALS']) |
454
|
|
|
|| isset($_REQUEST['ssi_theme']) && (int) $_REQUEST['ssi_theme'] == (int) $ssi_theme |
455
|
|
|
|| isset($_COOKIE['ssi_theme']) && (int) $_COOKIE['ssi_theme'] == (int) $ssi_theme |
456
|
|
|
|| isset($_REQUEST['ssi_layers'], $ssi_layers) && $_REQUEST['ssi_layers'] == $ssi_layers |
457
|
|
|
|| isset($_REQUEST['context'])) |
458
|
|
|
{ |
459
|
|
|
die('No access...'); |
|
|
|
|
460
|
|
|
} |
461
|
|
|
} |
462
|
|
|
} |
463
|
|
|
|
'Location: http' . (!emp...stall/' . $redirec_file
can contain request data and is used in response header context(s) leading to a potential security vulnerability.1 path for user data to reach this point
HTTP_HOST
from$_SERVER
in bootstrap.php on line 168
Response Splitting Attacks
Allowing an attacker to set a response header, opens your application to response splitting attacks; effectively allowing an attacker to send any response, he would like.
General Strategies to prevent injection
In general, it is advisable to prevent any user-data to reach this point. This can be done by white-listing certain values:
For numeric data, we recommend to explicitly cast the data: