common.inc.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. <?php
  2. /* vim: set expandtab sw=4 ts=4 sts=4: */
  3. /**
  4. * Misc stuff and REQUIRED by ALL the scripts.
  5. * MUST be included by every script
  6. *
  7. * Among other things, it contains the advanced authentication work.
  8. *
  9. * Order of sections for common.inc.php:
  10. *
  11. * the authentication libraries must be before the connection to db
  12. *
  13. * ... so the required order is:
  14. *
  15. * LABEL_variables_init
  16. * - initialize some variables always needed
  17. * LABEL_parsing_config_file
  18. * - parsing of the configuration file
  19. * LABEL_loading_language_file
  20. * - loading language file
  21. * LABEL_setup_servers
  22. * - check and setup configured servers
  23. * LABEL_theme_setup
  24. * - setting up themes
  25. *
  26. * - load of MySQL extension (if necessary)
  27. * - loading of an authentication library
  28. * - db connection
  29. * - authentication work
  30. *
  31. * @package PhpMyAdmin
  32. */
  33. use PhpMyAdmin\Config;
  34. use PhpMyAdmin\Core;
  35. use PhpMyAdmin\DatabaseInterface;
  36. use PhpMyAdmin\ErrorHandler;
  37. use PhpMyAdmin\LanguageManager;
  38. use PhpMyAdmin\Logging;
  39. use PhpMyAdmin\Message;
  40. use PhpMyAdmin\Plugins\AuthenticationPlugin;
  41. use PhpMyAdmin\Response;
  42. use PhpMyAdmin\Session;
  43. use PhpMyAdmin\ThemeManager;
  44. use PhpMyAdmin\Tracker;
  45. use PhpMyAdmin\Util;
  46. /**
  47. * block attempts to directly run this script
  48. */
  49. if (getcwd() == dirname(__FILE__)) {
  50. die('Attack stopped');
  51. }
  52. /**
  53. * Minimum PHP version; can't call Core::fatalError() which uses a
  54. * PHP 5 function, so cannot easily localize this message.
  55. */
  56. if (version_compare(PHP_VERSION, '5.5.0', 'lt')) {
  57. die(
  58. 'PHP 5.5+ is required. <br /> Currently installed version is: '
  59. . phpversion()
  60. );
  61. }
  62. /**
  63. * for verification in all procedural scripts under libraries
  64. */
  65. define('PHPMYADMIN', true);
  66. /**
  67. * Load vendor configuration.
  68. */
  69. require_once './libraries/vendor_config.php';
  70. /**
  71. * Load hash polyfill.
  72. */
  73. require_once './libraries/hash.lib.php';
  74. /**
  75. * Activate autoloader
  76. */
  77. if (! @is_readable(AUTOLOAD_FILE)) {
  78. die(
  79. 'File <tt>' . AUTOLOAD_FILE . '</tt> missing or not readable. <br />'
  80. . 'Most likely you did not run Composer to '
  81. . '<a href="https://docs.phpmyadmin.net/en/latest/setup.html#installing-from-git">install library files</a>.'
  82. );
  83. }
  84. require_once AUTOLOAD_FILE;
  85. /**
  86. * Load gettext functions.
  87. */
  88. PhpMyAdmin\MoTranslator\Loader::loadFunctions();
  89. /**
  90. * initialize the error handler
  91. */
  92. $GLOBALS['error_handler'] = new ErrorHandler();
  93. /**
  94. * Warning about missing PHP extensions.
  95. */
  96. Core::checkExtensions();
  97. /**
  98. * Configure required PHP settings.
  99. */
  100. Core::configure();
  101. /******************************************************************************/
  102. /* start procedural code label_start_procedural */
  103. Core::cleanupPathInfo();
  104. /******************************************************************************/
  105. /* parsing configuration file LABEL_parsing_config_file */
  106. /**
  107. * @global Config $GLOBALS['PMA_Config']
  108. * force reading of config file, because we removed sensitive values
  109. * in the previous iteration
  110. */
  111. $GLOBALS['PMA_Config'] = new Config(CONFIG_FILE);
  112. /**
  113. * include session handling after the globals, to prevent overwriting
  114. */
  115. if (! defined('PMA_NO_SESSION')) {
  116. Session::setUp($GLOBALS['PMA_Config'], $GLOBALS['error_handler']);
  117. }
  118. Core::populateRequestWithEncryptedQueryParams();
  119. /**
  120. * init some variables LABEL_variables_init
  121. */
  122. /**
  123. * holds parameters to be passed to next page
  124. * @global array $GLOBALS['url_params']
  125. */
  126. $GLOBALS['url_params'] = array();
  127. /**
  128. * holds page that should be displayed
  129. * @global string $GLOBALS['goto']
  130. */
  131. $GLOBALS['goto'] = '';
  132. // Security fix: disallow accessing serious server files via "?goto="
  133. if (Core::checkPageValidity($_REQUEST['goto'])) {
  134. $GLOBALS['goto'] = $_REQUEST['goto'];
  135. $GLOBALS['url_params']['goto'] = $_REQUEST['goto'];
  136. } else {
  137. $GLOBALS['PMA_Config']->removeCookie('goto');
  138. unset($_REQUEST['goto'], $_GET['goto'], $_POST['goto']);
  139. }
  140. /**
  141. * returning page
  142. * @global string $GLOBALS['back']
  143. */
  144. if (Core::checkPageValidity($_REQUEST['back'])) {
  145. $GLOBALS['back'] = $_REQUEST['back'];
  146. } else {
  147. $GLOBALS['PMA_Config']->removeCookie('back');
  148. unset($_REQUEST['back'], $_GET['back'], $_POST['back']);
  149. }
  150. /**
  151. * Check whether user supplied token is valid, if not remove any possibly
  152. * dangerous stuff from request.
  153. *
  154. * remember that some objects in the session with session_start and __wakeup()
  155. * could access this variables before we reach this point
  156. * f.e. PhpMyAdmin\Config: fontsize
  157. *
  158. * Check for token mismatch only if the Request method is POST
  159. * GET Requests would never have token and therefore checking
  160. * mis-match does not make sense
  161. *
  162. * @todo variables should be handled by their respective owners (objects)
  163. * f.e. lang, server in PhpMyAdmin\Config
  164. */
  165. $token_mismatch = true;
  166. $token_provided = false;
  167. if ($_SERVER['REQUEST_METHOD'] == 'POST') {
  168. if (Core::isValid($_POST['token'])) {
  169. $token_provided = true;
  170. $token_mismatch = ! @hash_equals($_SESSION[' PMA_token '], $_POST['token']);
  171. }
  172. if ($token_mismatch) {
  173. /* Warn in case the mismatch is result of failed setting of session cookie */
  174. if (isset($_POST['set_session']) && $_POST['set_session'] != session_id()) {
  175. trigger_error(
  176. __(
  177. 'Failed to set session cookie. Maybe you are using '
  178. . 'HTTP instead of HTTPS to access phpMyAdmin.'
  179. ),
  180. E_USER_ERROR
  181. );
  182. }
  183. /**
  184. * We don't allow any POST operation parameters if the token is mismatched
  185. * or is not provided
  186. */
  187. $whitelist = array('ajax_request');
  188. PhpMyAdmin\Sanitize::removeRequestVars($whitelist);
  189. }
  190. }
  191. /**
  192. * current selected database
  193. * @global string $GLOBALS['db']
  194. */
  195. Core::setGlobalDbOrTable('db');
  196. /**
  197. * current selected table
  198. * @global string $GLOBALS['table']
  199. */
  200. Core::setGlobalDbOrTable('table');
  201. /**
  202. * Store currently selected recent table.
  203. * Affect $GLOBALS['db'] and $GLOBALS['table']
  204. */
  205. if (Core::isValid($_REQUEST['selected_recent_table'])) {
  206. $recent_table = json_decode($_REQUEST['selected_recent_table'], true);
  207. $GLOBALS['db']
  208. = (array_key_exists('db', $recent_table) && is_string($recent_table['db'])) ?
  209. $recent_table['db'] : '';
  210. $GLOBALS['url_params']['db'] = $GLOBALS['db'];
  211. $GLOBALS['table']
  212. = (array_key_exists('table', $recent_table) && is_string($recent_table['table'])) ?
  213. $recent_table['table'] : '';
  214. $GLOBALS['url_params']['table'] = $GLOBALS['table'];
  215. }
  216. /**
  217. * SQL query to be executed
  218. * @global string $GLOBALS['sql_query']
  219. */
  220. $GLOBALS['sql_query'] = '';
  221. if (Core::isValid($_POST['sql_query'])) {
  222. $GLOBALS['sql_query'] = $_POST['sql_query'];
  223. }
  224. //$_REQUEST['set_theme'] // checked later in this file LABEL_theme_setup
  225. //$_REQUEST['server']; // checked later in this file
  226. //$_REQUEST['lang']; // checked by LABEL_loading_language_file
  227. /******************************************************************************/
  228. /* loading language file LABEL_loading_language_file */
  229. /**
  230. * lang detection is done here
  231. */
  232. $language = LanguageManager::getInstance()->selectLanguage();
  233. $language->activate();
  234. /**
  235. * check for errors occurred while loading configuration
  236. * this check is done here after loading language files to present errors in locale
  237. */
  238. $GLOBALS['PMA_Config']->checkPermissions();
  239. $GLOBALS['PMA_Config']->checkErrors();
  240. /* Check server configuration */
  241. Core::checkConfiguration();
  242. /* Check request for possible attacks */
  243. Core::checkRequest();
  244. /******************************************************************************/
  245. /* setup servers LABEL_setup_servers */
  246. $GLOBALS['PMA_Config']->checkServers();
  247. /**
  248. * current server
  249. * @global integer $GLOBALS['server']
  250. */
  251. $GLOBALS['server'] = $GLOBALS['PMA_Config']->selectServer();
  252. $GLOBALS['url_params']['server'] = $GLOBALS['server'];
  253. /**
  254. * BC - enable backward compatibility
  255. * exports all configuration settings into $GLOBALS ($GLOBALS['cfg'])
  256. */
  257. $GLOBALS['PMA_Config']->enableBc();
  258. /******************************************************************************/
  259. /* setup themes LABEL_theme_setup */
  260. ThemeManager::initializeTheme();
  261. if (! defined('PMA_MINIMUM_COMMON')) {
  262. /**
  263. * save some settings in cookies
  264. * @todo should be done in PhpMyAdmin\Config
  265. */
  266. $GLOBALS['PMA_Config']->setCookie('pma_lang', $GLOBALS['lang']);
  267. ThemeManager::getInstance()->setThemeCookie();
  268. if (! empty($cfg['Server'])) {
  269. /**
  270. * Loads the proper database interface for this server
  271. */
  272. DatabaseInterface::load();
  273. // get LoginCookieValidity from preferences cache
  274. // no generic solution for loading preferences from cache as some settings
  275. // need to be kept for processing in
  276. // PhpMyAdmin\Config::loadUserPreferences()
  277. $cache_key = 'server_' . $GLOBALS['server'];
  278. if (isset($_SESSION['cache'][$cache_key]['userprefs']['LoginCookieValidity'])
  279. ) {
  280. $value
  281. = $_SESSION['cache'][$cache_key]['userprefs']['LoginCookieValidity'];
  282. $GLOBALS['PMA_Config']->set('LoginCookieValidity', $value);
  283. $GLOBALS['cfg']['LoginCookieValidity'] = $value;
  284. unset($value);
  285. }
  286. unset($cache_key);
  287. // Gets the authentication library that fits the $cfg['Server'] settings
  288. // and run authentication
  289. /**
  290. * the required auth type plugin
  291. */
  292. $auth_class = 'PhpMyAdmin\\Plugins\\Auth\\Authentication' . ucfirst(strtolower($cfg['Server']['auth_type']));
  293. if (! @class_exists($auth_class)) {
  294. Core::fatalError(
  295. __('Invalid authentication method set in configuration:')
  296. . ' ' . $cfg['Server']['auth_type']
  297. );
  298. }
  299. if (isset($_POST['pma_password']) && strlen($_POST['pma_password']) > 256) {
  300. $_POST['pma_password'] = substr($_POST['pma_password'], 0, 256);
  301. }
  302. $auth_plugin = new $auth_class();
  303. $auth_plugin->authenticate();
  304. // Try to connect MySQL with the control user profile (will be used to
  305. // get the privileges list for the current user but the true user link
  306. // must be open after this one so it would be default one for all the
  307. // scripts)
  308. $controllink = false;
  309. if ($cfg['Server']['controluser'] != '') {
  310. $controllink = $GLOBALS['dbi']->connect(
  311. DatabaseInterface::CONNECT_CONTROL
  312. );
  313. }
  314. // Connects to the server (validates user's login)
  315. /** @var DatabaseInterface $userlink */
  316. $userlink = $GLOBALS['dbi']->connect(DatabaseInterface::CONNECT_USER);
  317. if ($userlink === false) {
  318. $auth_plugin->showFailure('mysql-denied');
  319. }
  320. if (! $controllink) {
  321. /*
  322. * Open separate connection for control queries, this is needed
  323. * to avoid problems with table locking used in main connection
  324. * and phpMyAdmin issuing queries to configuration storage, which
  325. * is not locked by that time.
  326. */
  327. $controllink = $GLOBALS['dbi']->connect(
  328. DatabaseInterface::CONNECT_USER,
  329. null,
  330. DatabaseInterface::CONNECT_CONTROL
  331. );
  332. }
  333. $auth_plugin->rememberCredentials();
  334. $auth_plugin->checkTwoFactor();
  335. /* Log success */
  336. Logging::logUser($cfg['Server']['user']);
  337. if ($GLOBALS['dbi']->getVersion() < $cfg['MysqlMinVersion']['internal']) {
  338. Core::fatalError(
  339. __('You should upgrade to %s %s or later.'),
  340. array('MySQL', $cfg['MysqlMinVersion']['human'])
  341. );
  342. }
  343. // Sets the default delimiter (if specified).
  344. if (!empty($_REQUEST['sql_delimiter'])) {
  345. PhpMyAdmin\SqlParser\Lexer::$DEFAULT_DELIMITER = $_REQUEST['sql_delimiter'];
  346. }
  347. // TODO: Set SQL modes too.
  348. } else { // end server connecting
  349. $response = Response::getInstance();
  350. $response->getHeader()->disableMenuAndConsole();
  351. $response->getFooter()->setMinimal();
  352. }
  353. /**
  354. * check if profiling was requested and remember it
  355. * (note: when $cfg['ServerDefault'] = 0, constant is not defined)
  356. */
  357. if (isset($_REQUEST['profiling'])
  358. && Util::profilingSupported()
  359. ) {
  360. $_SESSION['profiling'] = true;
  361. } elseif (isset($_REQUEST['profiling_form'])) {
  362. // the checkbox was unchecked
  363. unset($_SESSION['profiling']);
  364. }
  365. /**
  366. * Inclusion of profiling scripts is needed on various
  367. * pages like sql, tbl_sql, db_sql, tbl_select
  368. */
  369. $response = Response::getInstance();
  370. if (isset($_SESSION['profiling'])) {
  371. $scripts = $response->getHeader()->getScripts();
  372. $scripts->addFile('chart.js');
  373. $scripts->addFile('vendor/jqplot/jquery.jqplot.js');
  374. $scripts->addFile('vendor/jqplot/plugins/jqplot.pieRenderer.js');
  375. $scripts->addFile('vendor/jqplot/plugins/jqplot.highlighter.js');
  376. $scripts->addFile('vendor/jquery/jquery.tablesorter.js');
  377. }
  378. /*
  379. * There is no point in even attempting to process
  380. * an ajax request if there is a token mismatch
  381. */
  382. if ($response->isAjax() && $_SERVER['REQUEST_METHOD'] == 'POST' && $token_mismatch) {
  383. $response->setRequestStatus(false);
  384. $response->addJSON(
  385. 'message',
  386. Message::error(__('Error: Token mismatch'))
  387. );
  388. exit;
  389. }
  390. }
  391. // load user preferences
  392. $GLOBALS['PMA_Config']->loadUserPreferences();
  393. /* Tell tracker that it can actually work */
  394. Tracker::enable();
  395. if (! defined('PMA_MINIMUM_COMMON')
  396. && ! empty($GLOBALS['server'])
  397. && isset($GLOBALS['cfg']['ZeroConf'])
  398. && $GLOBALS['cfg']['ZeroConf'] == true
  399. ) {
  400. $GLOBALS['dbi']->postConnectControl();
  401. }