From 1e8329986ef4d06a9bb7550e24f4dacc7715fb5b Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 4 May 2021 17:32:26 +0200 Subject: [main+Session] Move session from /tmp/ to session table --- inc/session.inc.php | 133 +++++++++++++-------- inc/user.inc.php | 10 +- inc/util.inc.php | 1 - modules-available/main/install.inc.php | 11 ++ .../rebootcontrol/inc/rebootcontrol.inc.php | 1 - modules-available/rebootcontrol/pages/exec.inc.php | 1 - modules-available/session/hooks/cron.inc.php | 6 + .../sysconfig/addmodule_branding.inc.php | 2 - .../sysconfig/addmodule_custommodule.inc.php | 2 - .../sysconfig/addmodule_screensaver.inc.php | 2 - modules-available/syslog/page.inc.php | 17 ++- modules-available/vmstore/page.inc.php | 2 +- 12 files changed, 115 insertions(+), 73 deletions(-) create mode 100644 modules-available/session/hooks/cron.inc.php diff --git a/inc/session.inc.php b/inc/session.inc.php index cb52cd38..f06cd580 100644 --- a/inc/session.inc.php +++ b/inc/session.inc.php @@ -2,18 +2,17 @@ require_once('config.php'); -@mkdir(CONFIG_SESSION_DIR, 0700, true); -@chmod(CONFIG_SESSION_DIR, 0700); -if (!is_writable(CONFIG_SESSION_DIR)) die('Config error: Session Path not writable!'); - class Session { private static $sid = false; private static $data = false; + private static $dataChanged = false; + private static $userId = 0; - private static function generateSessionId($salt) + private static function generateSessionId(string $salt) { - if (self::$sid !== false) Util::traceError('Error: Asked to generate session id when already set.'); + if (self::$sid !== false) + Util::traceError('Error: Asked to generate session id when already set.'); self::$sid = sha1($salt . ',' . mt_rand(0, 65535) . $_SERVER['REMOTE_ADDR'] @@ -27,26 +26,40 @@ class Session ); } - public static function create($salt = '') + public static function create(string $salt, int $userId, bool $fixedAddress) { self::generateSessionId($salt); - self::$data = array(); + self::$data = []; + self::$userId = $userId; + Database::exec("INSERT INTO session (sid, userid, dateline, lastip, fixedip, data) + VALUES (:sid, :userid, 0, '', :fixedip, '')", [ + 'sid' => self::$sid, + 'userid' => $userId, + 'fixedip' => $fixedAddress ? 1 : 0, + ]); } - public static function load() + public static function load(): bool { // Try to load session id from cookie - if (!self::loadSessionId()) return false; + if (!self::loadSessionId()) + return false; // Succeeded, now try to load session data. If successful, job is done - if (self::readSessionData()) return true; + if (self::readSessionData()) + return true; // Loading session data failed - self::delete(); return false; } - public static function get($key) + public static function getUserId(): int + { + return self::$userId; + } + + public static function get(string $key) { - if (!isset(self::$data[$key]) || !is_array(self::$data[$key])) return false; + if (!isset(self::$data[$key]) || !is_array(self::$data[$key])) + return false; return self::$data[$key][0]; } @@ -55,30 +68,37 @@ class Session * @param mixed $value data to store for key, false = delete * @param int|false $validMinutes validity in minutes, or false = forever */ - public static function set($key, $value, $validMinutes = false) + public static function set(string $key, $value, $validMinutes = 60) { - if (self::$data === false) Util::traceError('Tried to set session data with no active session'); + if (self::$data === false) + Util::traceError('Tried to set session data with no active session'); if ($value === false) { unset(self::$data[$key]); } else { self::$data[$key] = [$value, $validMinutes === false ? false : time() + $validMinutes * 60]; } + self::$dataChanged = true; } - private static function loadSessionId() + private static function loadSessionId(): bool { - if (self::$sid !== false) die('Error: Asked to load session id when already set.'); - if (empty($_COOKIE['sid'])) return false; + if (self::$sid !== false) + Util::traceError('Error: Asked to load session id when already set.'); + if (empty($_COOKIE['sid'])) + return false; $id = preg_replace('/[^a-zA-Z0-9]/', '', $_COOKIE['sid']); - if (empty($id)) return false; + if (empty($id)) + return false; self::$sid = $id; return true; } public static function delete() { - if (self::$sid === false) return; - @unlink(self::getSessionFile()); + if (self::$sid === false) + return; + Database::exec("DELETE FROM session WHERE sid = :sid", + ['sid' => self::$sid]); self::deleteCookie(); self::$sid = false; self::$data = false; @@ -88,47 +108,58 @@ class Session { Util::clearCookie('sid'); } - - private static function getSessionFile() - { - if (self::$sid === false) Util::traceError('Error: Tried to access session file when no session id was set.'); - return CONFIG_SESSION_DIR . '/' . self::$sid; - } - private static function readSessionData() + private static function readSessionData(): bool { - if (self::$data !== false) Util::traceError('Tried to call read session data twice'); - $sessionfile = self::getSessionFile(); - if (!is_readable($sessionfile) || filemtime($sessionfile) + CONFIG_SESSION_TIMEOUT < time()) { - @unlink($sessionfile); - return false; - } - self::$data = @unserialize(@file_get_contents($sessionfile)); - if (self::$data === false) - return false; + if (self::$data !== false) + Util::traceError('Tried to call read session data twice'); + $row = Database::queryFirst("SELECT userid, dateline, lastip, fixedip, data FROM session WHERE sid = :sid", + ['sid' => self::$sid]); $now = time(); - $save = false; + if ($row === false || $row['dateline'] < $now) { + self::delete(); + return false; + } + if ($row['fixedip'] && $row['lastip'] !== $_SERVER['REMOTE_ADDR']) { + return false; // Ignore but don't invalidate + } + self::$userId = $row['userid']; + self::$data = @json_decode($row['data'], true); + if (!is_array(self::$data)) { + self::$data = []; + } foreach (array_keys(self::$data) as $key) { if (self::$data[$key][1] !== false && self::$data[$key][1] < $now) { unset(self::$data[$key]); - $save = true; + self::$dataChanged = true; } } - if ($save) { - self::save(); - } return true; } - public static function save() + public static function saveInternal() { - if (self::$sid === false || self::$data === false) return; //Util::traceError('Called saveSession with no active session'); - $sessionfile = self::getSessionFile(); - $ret = @file_put_contents($sessionfile, @serialize(self::$data)); - if (!$ret) Util::traceError('Storing session data in ' . $sessionfile . ' failed.'); - Util::clearCookie('sid'); - $ret = setcookie('sid', self::$sid, time() + CONFIG_SESSION_TIMEOUT, null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); - if (!$ret) Util::traceError('Error: Could not set Cookie for Client (headers already sent)'); + $now = time(); + $args = [ + 'dateline' => $now + CONFIG_SESSION_TIMEOUT, + 'lastip' => $_SERVER['REMOTE_ADDR'], + ]; + if (self::$dataChanged) { + $args['data'] = json_encode(self::$data); + } + $query = "UPDATE session SET " . implode(', ', array_map(function ($key) { + return "$key = :$key"; + }, array_keys($args))) . " WHERE sid = :sid"; + $args['sid'] = self::$sid; + Database::exec($query, $args); + $ret = setcookie('sid', self::$sid, $now + CONFIG_SESSION_TIMEOUT, + null, null, !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] != 'off', true); + if (!$ret) + Util::traceError('Error: Could not set Cookie for Client (headers already sent)'); } + } +register_shutdown_function(function () { + Session::saveInternal(); +}); diff --git a/inc/user.inc.php b/inc/user.inc.php index 2ad256af..46cc6012 100644 --- a/inc/user.inc.php +++ b/inc/user.inc.php @@ -113,8 +113,8 @@ class User if (self::isLoggedIn()) return true; if (Session::load()) { - $uid = Session::get('uid'); - if ($uid === false || $uid < 1) + $uid = Session::getUserId(); + if ($uid < 1) self::logout(); self::$user = Database::queryFirst('SELECT * FROM user WHERE userid = :uid LIMIT 1', array(':uid' => $uid)); if (self::$user === false) @@ -149,8 +149,7 @@ class User return false; if (!Crypto::verify($pass, $ret['passwd'])) return false; - Session::create($ret['passwd']); - Session::set('uid', $ret['userid']); + Session::create($ret['passwd'], $ret['userid'], false); Session::set('token', md5($ret['passwd'] . ',' . rand() . ',' . time() . ',' @@ -159,8 +158,7 @@ class User . rand() . ',' . $_SERVER['REMOTE_PORT'] . ',' . rand() . ',' - . $_SERVER['HTTP_USER_AGENT'])); - Session::save(); + . $_SERVER['HTTP_USER_AGENT']), false); return true; } diff --git a/inc/util.inc.php b/inc/util.inc.php index fbc894df..81c7d807 100644 --- a/inc/util.inc.php +++ b/inc/util.inc.php @@ -158,7 +158,6 @@ SADFACE; if ($location === false) { $location = preg_replace('/([&?])message\[\]\=[^&]*/', '\1', $_SERVER['REQUEST_URI']); } - Session::save(); $messages = Message::toRequest(); if ($preferRedirectPost && ($redirect = Request::post('redirect', false, 'string')) !== false diff --git a/modules-available/main/install.inc.php b/modules-available/main/install.inc.php index 92ad4db1..fe572487 100644 --- a/modules-available/main/install.inc.php +++ b/modules-available/main/install.inc.php @@ -48,6 +48,17 @@ $res[] = tableCreate('user', " UNIQUE KEY `login` (`login`) "); +$res[] = tableCreate('session', " + `sid` char(50) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, + `userid` int(10) unsigned NOT NULL, + `dateline` int(10) unsigned NOT NULL DEFAULT '0', + `lastip` varchar(45) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, + `fixedip` tinyint(1) unsigned NOT NULL DEFAULT '0', + `data` blob NOT NULL, + PRIMARY KEY (`sid`), + KEY `dateline` (`dateline`) +"); + // Update path // ####################### diff --git a/modules-available/rebootcontrol/inc/rebootcontrol.inc.php b/modules-available/rebootcontrol/inc/rebootcontrol.inc.php index a8018004..da1dd69a 100644 --- a/modules-available/rebootcontrol/inc/rebootcontrol.inc.php +++ b/modules-available/rebootcontrol/inc/rebootcontrol.inc.php @@ -494,7 +494,6 @@ class RebootControl return; $id = mt_rand(); Session::set('exec-' . $id, $machines, 60); - Session::save(); Util::redirect('?do=rebootcontrol&show=exec&what=prepare&id=' . $id); } diff --git a/modules-available/rebootcontrol/pages/exec.inc.php b/modules-available/rebootcontrol/pages/exec.inc.php index e5fe3cd8..6b5ea407 100644 --- a/modules-available/rebootcontrol/pages/exec.inc.php +++ b/modules-available/rebootcontrol/pages/exec.inc.php @@ -46,7 +46,6 @@ class SubPage return; } Session::set('exec-' . $id, false); - Session::save(); Render::addTemplate('exec-enter-command', ['clients' => $machines, 'id' => $id]); } diff --git a/modules-available/session/hooks/cron.inc.php b/modules-available/session/hooks/cron.inc.php new file mode 100644 index 00000000..e2cd46e6 --- /dev/null +++ b/modules-available/session/hooks/cron.inc.php @@ -0,0 +1,6 @@ +tarFile); - Session::save(); } protected function renderInternal() @@ -227,7 +226,6 @@ class Branding_Finish extends AddModule_Base Util::redirect('?do=SysConfig&action=addmodule&step=Branding_Start'); Session::set('logo_tgz', false); Session::set('logo_name', false); - Session::save(); // Yay if ($this->edit !== false) Message::addSuccess('module-edited'); diff --git a/modules-available/sysconfig/addmodule_custommodule.inc.php b/modules-available/sysconfig/addmodule_custommodule.inc.php index f7ab863e..13794e83 100644 --- a/modules-available/sysconfig/addmodule_custommodule.inc.php +++ b/modules-available/sysconfig/addmodule_custommodule.inc.php @@ -83,7 +83,6 @@ class CustomModule_ProcessUpload extends AddModule_Base 'title' => $title, 'userGroupWarn' => $userGroupWarn, )); - Session::save(); } } @@ -135,7 +134,6 @@ class CustomModule_CompressModule extends AddModule_Base elseif (!$module->generate($this->edit === false, NULL, 200)) Util::redirect('?do=SysConfig&action=addmodule&step=CustomModule_Start'); Session::set('mod_temp', false); - Session::save(); // Yay if ($this->edit !== false) Message::addSuccess('module-edited'); diff --git a/modules-available/sysconfig/addmodule_screensaver.inc.php b/modules-available/sysconfig/addmodule_screensaver.inc.php index 8e5c5d28..9641bab3 100644 --- a/modules-available/sysconfig/addmodule_screensaver.inc.php +++ b/modules-available/sysconfig/addmodule_screensaver.inc.php @@ -47,7 +47,6 @@ class Screensaver_Start extends AddModule_Base } $this->session_data['next'] = 'idle-kill'; Session::set('data', $this->session_data); - Session::save(); } protected function renderInternal() @@ -85,7 +84,6 @@ class Screensaver_Text extends AddModule_Base $next = Request::post('next', $this->session_data['next'], 'string'); $this->session_data['next'] = $next; Session::set('data', $this->session_data); - Session::save(); if ($next === 'finish') diff --git a/modules-available/syslog/page.inc.php b/modules-available/syslog/page.inc.php index 6868994e..410a1ed7 100644 --- a/modules-available/syslog/page.inc.php +++ b/modules-available/syslog/page.inc.php @@ -26,14 +26,19 @@ class Page_SysLog extends Page Util::redirect('?do=syslog'); } if (Request::isPost()) { - $search = Request::any('search'); - $filter = Request::any('filter'); + $search = Request::any('search', false, 'string'); + $filter = Request::any('filter', false, 'string'); $not = Request::any('not', false, 'bool'); $machineuuid = Request::any('machineuuid'); - Session::set('log_search', $search); - Session::set('log_filter', $filter); - Session::set('log_not', $not); - Session::save(); + if (empty($search)) { + $search = false; + } + if (empty($filter)) { + $filter = false; + } + Session::set('log_search', $search, false); + Session::set('log_filter', $filter, false); + Session::set('log_not', $not, false); Util::redirect('?do=syslog&' . http_build_query(compact('search', 'filter', 'not', 'machineuuid'))); } User::assertPermission('*'); diff --git a/modules-available/vmstore/page.inc.php b/modules-available/vmstore/page.inc.php index 39f6abdc..08d56d96 100644 --- a/modules-available/vmstore/page.inc.php +++ b/modules-available/vmstore/page.inc.php @@ -44,7 +44,7 @@ class Page_VmStore extends Page // Remove rw setting if ($key === 'cifsopts' || $key === 'nfsopts') { $vmstore[$key] = preg_replace('/\s+,\s+/', ',', $vmstore[$key]); - $vmstore[$key] = preg_replace('/^rw,|,rw$/', '', str_replace(',rw,', ',', $vmstore[$key])); + $vmstore[$key] = preg_replace('/^rw ,|,rw$/', '', str_replace(',rw,', ',', $vmstore[$key])); } } $storetype = $vmstore['storetype']; -- cgit v1.2.3-55-g7522