diff options
author | Remi Collet <remi@remirepo.net> | 2019-03-27 16:06:47 +0100 |
---|---|---|
committer | Remi Collet <remi@remirepo.net> | 2019-03-27 16:06:47 +0100 |
commit | 6c1dfcb9214ecbf010719a846c8b3b8ea38f2653 (patch) | |
tree | b5ac692ee2b863e32edc58a95f182e78f1114bd7 | |
parent | 87c0348084cb603dd1e03474502c3ab6366e273f (diff) |
add security fix backported from 9.4.1:
[security] Bad chevrons rendering on dropdowns
[security] Iframe and forms are rendered in rich text contents
[security] Type juggling authentication bypass
[security] Malicious images upload
[security] Password token date was not reset
[security] Prevent timed attack and enforce cookie security
-rw-r--r-- | glpi-security1.patch | 432 | ||||
-rw-r--r-- | glpi-security2.patch | 292 | ||||
-rw-r--r-- | glpi.spec | 22 |
3 files changed, 744 insertions, 2 deletions
diff --git a/glpi-security1.patch b/glpi-security1.patch new file mode 100644 index 0000000..f33fc96 --- /dev/null +++ b/glpi-security1.patch @@ -0,0 +1,432 @@ +From c5314dd86d6560865670940b59ac0fbb97225bb4 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Anne?= <cedric.anne@gmail.com> +Date: Tue, 26 Feb 2019 13:46:06 +0100 +Subject: [PATCH 01/10] Fix chevrons display in select2 rendering + +--- + inc/html.class.php | 10 ++++++++++ + js/common.js | 16 ++++++++++++---- + 2 files changed, 22 insertions(+), 4 deletions(-) + +diff --git a/inc/html.class.php b/inc/html.class.php +index 760ffe164b..e5907c8d5b 100644 +--- a/inc/html.class.php ++++ b/inc/html.class.php +@@ -4329,6 +4329,11 @@ static function jsAdaptDropdown($id, $params = []) { + if (typeof data.text === 'string' + && data.text.toUpperCase().indexOf(params.term.toUpperCase()) >= 0 + ) { ++ if (data.text.indexOf('>') !== -1 || data.text.indexOf('<') !== -1) { ++ // escape text, if it contains chevrons (can already be escaped prior to this point :/) ++ data.text = jQuery.fn.select2.defaults.defaults.escapeMarkup(data.text); ++ } ++ + return data; + } + return null; +@@ -4341,6 +4346,11 @@ static function jsAdaptDropdown($id, $params = []) { + if (child.text.toUpperCase().indexOf(params.term.toUpperCase()) != -1 + || data.text.toUpperCase().indexOf(params.term.toUpperCase()) != -1 + ) { ++ ++ if (child.text.indexOf('>') !== -1 || child.text.indexOf('<') !== -1) { ++ // escape text, if it contains chevrons (can already be escaped prior to this point :/) ++ child.text = jQuery.fn.select2.defaults.defaults.escapeMarkup(child.text); ++ } + filteredChildren.push(child); + } + }); +diff --git a/js/common.js b/js/common.js +index c08623434c..15cf04b200 100644 +--- a/js/common.js ++++ b/js/common.js +@@ -948,17 +948,25 @@ function markMatch (text, term) { + * Function that renders select2 results. + */ + var templateResult = function(result) { +- if (!result.id) { +- return result.text; ++ if (!result.text) { ++ return null; + } + + var _elt = $('<span></span>'); + _elt.attr('title', result.title); + +- var markup=[result.text]; ++ var text = result.text; ++ if (text.indexOf('>') !== -1 || text.indexOf('<') !== -1) { ++ // escape text, if it contains chevrons (can already be escaped prior to this point :/) ++ text = jQuery.fn.select2.defaults.defaults.escapeMarkup(result.text); ++ }; ++ ++ if (!result.id) { ++ return text; ++ } + + var _term = query.term || ''; +- var markup = markMatch(result.text, _term); ++ var markup = markMatch(text, _term); + + if (result.level) { + var a=''; + +From 2c5d9f80f64a1f5ef4c62af8be5d24b812b75ecc Mon Sep 17 00:00:00 2001 +From: Johan Cwiklinski <jcwiklinski@teclib.com> +Date: Tue, 5 Mar 2019 12:49:05 +0100 +Subject: [PATCH 02/10] Disallow all on attributes + +--- + inc/html.class.php | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/inc/html.class.php b/inc/html.class.php +index e5907c8d5b..f9aa6532dd 100644 +--- a/inc/html.class.php ++++ b/inc/html.class.php +@@ -3550,6 +3550,9 @@ static function initEditorSystem($name, $rand = '', $display = true, $readonly = + // init editor + tinyMCE.init({ + language: '$language', ++ invalid_elements: 'form,iframe,script,@[onclick|ondblclick|' ++ + 'onmousedown|onmouseup|onmouseover|onmousemove|onmouseout|onkeypress|' ++ + 'onkeydown|onkeyup]', + browser_spellcheck: true, + mode: 'exact', + elements: '$name', + +From a330e5b49f46680cf9fb877fdac7a6e44eff9115 Mon Sep 17 00:00:00 2001 +From: Johan Cwiklinski <jcwiklinski@teclib.com> +Date: Mon, 4 Mar 2019 16:15:04 +0100 +Subject: [PATCH 03/10] Strict check + +--- + inc/auth.class.php | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/inc/auth.class.php b/inc/auth.class.php +index 323b3b94a2..707d7ab314 100644 +--- a/inc/auth.class.php ++++ b/inc/auth.class.php +@@ -276,14 +276,14 @@ static function checkPassword($pass, $hash) { + $ok = password_verify($pass, $hash); + + } else if (strlen($hash)==32) { +- $ok = md5($pass) == $hash; ++ $ok = md5($pass) === $hash; + + } else if (strlen($hash)==40) { +- $ok = sha1($pass) == $hash; ++ $ok = sha1($pass) === $hash; + + } else { + $salt = substr($hash, 0, 8); +- $ok = ($salt.sha1($salt.$pass) == $hash); ++ $ok = ($salt.sha1($salt.$pass) === $hash); + } + + return $ok; + +From f8959e587db32361c3013898c9f223a4151ada33 Mon Sep 17 00:00:00 2001 +From: Johan Cwiklinski <jcwiklinski@teclib.com> +Date: Tue, 12 Mar 2019 14:44:53 +0100 +Subject: [PATCH 04/10] Use exif if present to check if file is image, or + fallback with W on fileinfo + +--- + inc/config.class.php | 3 +++ + inc/document.class.php | 13 +++++++++++-- + tests/functionnal/Document.php | 20 +++++++------------- + tests/notanimage.jpg | 3 +++ + 4 files changed, 24 insertions(+), 15 deletions(-) + create mode 100644 tests/notanimage.jpg + +diff --git a/inc/config.class.php b/inc/config.class.php +index b648d53181..8797b5bd4c 100644 +--- a/inc/config.class.php ++++ b/inc/config.class.php +@@ -2456,6 +2456,9 @@ static function checkExtensions($list = null) { + 'CAS' => [ + 'required' => false, + 'class' => 'phpCAS' ++ ], ++ 'exif' => [ ++ 'required' => false + ] + ]; + } else { +diff --git a/inc/document.class.php b/inc/document.class.php +index 8072dac9f2..faca1a93ee 100644 +--- a/inc/document.class.php ++++ b/inc/document.class.php +@@ -1497,8 +1497,17 @@ static function getImageTag($string) { + * @return boolean + */ + public static function isImage($file) { +- $ext = strtolower(pathinfo($file, PATHINFO_EXTENSION)); +- return (in_array($ext, ['jpg', 'jpeg', 'png', 'bmp', 'gif'])); ++ if (extension_loaded('exif')) { ++ $etype = exif_imagetype($file); ++ return in_array($etype, [IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG, IMAGETYPE_BMP]); ++ } else { ++ Toolbox::logWarning('For security reasons, you should consider using exif PHP extension to properly check images.'); ++ $fileinfo = finfo_open(FILEINFO_MIME_TYPE); ++ return in_array( ++ finfo_file($fileinfo, $file), ++ ['image/jpeg', 'image/png','image/gif', 'image/bmp'] ++ ); ++ } + } + + /** +diff --git a/tests/functionnal/Document.php b/tests/functionnal/Document.php +index a00ca4b57f..1757ebc8e6 100644 +--- a/tests/functionnal/Document.php ++++ b/tests/functionnal/Document.php +@@ -215,25 +215,19 @@ public function testGetImageTag() { + + protected function isImageProvider() { + return [ +- ['PNG', true], +- ['png', true], +- ['JPG', true], +- ['jpg', true], +- ['jpeg', true], +- ['JPEG', true], +- ['bmp', true], +- ['BMP', true], +- ['gif', true], +- ['GIF', true], +- ['SVG', false] ++ [__FILE__, false], ++ [__DIR__ . "/../../pics/add_dropdown.png", true], ++ [__DIR__ . "/../../pics/corners.gif", true], ++ [__DIR__ . "/../../pics/PICS-AUTHORS.txt", false], ++ [__DIR__ . "/../notanimage.jpg", false] + ]; + } + + /** + * @dataProvider isImageProvider + */ +- public function testIsImage($ext, $expected) { +- $this->variable(\Document::isImage('myfile.' . $ext))->isIdenticalTo($expected); ++ public function testIsImage($file, $expected) { ++ $this->boolean(\Document::isImage($file))->isIdenticalTo($expected); + } + + /** +diff --git a/tests/notanimage.jpg b/tests/notanimage.jpg +new file mode 100644 +index 0000000000..d2dbc0fe33 +--- /dev/null ++++ b/tests/notanimage.jpg +@@ -0,0 +1,3 @@ ++<?php ++ ++echo 'This is not an image.'; + +From 5d11af11e08cc16d52083fe4a13f64f5f1a332d2 Mon Sep 17 00:00:00 2001 +From: Johan Cwiklinski <jcwiklinski@teclib.com> +Date: Tue, 12 Mar 2019 10:59:54 +0100 +Subject: [PATCH 05/10] Password token date was not removed + +--- + inc/user.class.php | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/inc/user.class.php b/inc/user.class.php +index e6ebb3a88d..fdc9d8b0ac 100644 +--- a/inc/user.class.php ++++ b/inc/user.class.php +@@ -4355,7 +4355,7 @@ public function updateForgottenPassword(array $input) { + } + $input2 = [ + 'password_forget_token' => '', +- 'password_forget_token_date' => null, ++ 'password_forget_token_date' => 'NULL', + 'id' => $this->fields['id'] + ]; + $this->update($input2); + +From 1ae67932a3de9349fbe5f0cd4d10d9a81a811f9d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Anne?= <cedric.anne@gmail.com> +Date: Thu, 14 Mar 2019 17:22:48 +0100 +Subject: [PATCH 06/10] Fix ITIL image path + +--- + inc/ticket.class.php | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/inc/ticket.class.php b/inc/ticket.class.php +index b414f85583..c9608c84e9 100644 +--- a/inc/ticket.class.php ++++ b/inc/ticket.class.php +@@ -7249,7 +7249,7 @@ function showTimeline($rand) { + + echo "<a href='".$CFG_GLPI['root_doc']."/front/document.send.php?docid=".$item_i['id'] + ."&tickets_id=".$this->getID()."' target='_blank'>$filename"; +- if (Document::isImage($filename)) { ++ if (Document::isImage(GLPI_DOC_DIR . '/' . $item_i['filepath'])) { + echo "<div class='timeline_img_preview'>"; + echo "<img src='".$CFG_GLPI['root_doc']."/front/document.send.php?docid=".$item_i['id'] + ."&tickets_id=".$this->getID()."&context=timeline'/>"; + +From cc1e2b02288635a4692bef5d2a7598862eafa4d1 Mon Sep 17 00:00:00 2001 +From: Johan Cwiklinski <jcwiklinski@teclib.com> +Date: Mon, 18 Mar 2019 19:27:04 +0100 +Subject: [PATCH 08/10] Update security-checker + +--- + composer.json | 2 +- + composer.lock | 21 +++++++++++---------- + 2 files changed, 12 insertions(+), 11 deletions(-) + +diff --git a/composer.json b/composer.json +index d1c3ee858b..66f6b52643 100644 +--- a/composer.json ++++ b/composer.json +@@ -43,7 +43,7 @@ + "patchwork/jsqueeze": "^2.0", + "atoum/atoum": "^3.3", + "atoum/telemetry-extension": "^1.0", +- "sensiolabs/security-checker": "^4.1", ++ "sensiolabs/security-checker": "^5.0", + "fzaninotto/Faker": "^1.7", + "jakub-onderka/php-parallel-lint": "^1.0" + }, +diff --git a/composer.lock b/composer.lock +index 467f8ce42d..4ce22d532d 100644 +--- a/composer.lock ++++ b/composer.lock +@@ -1,10 +1,10 @@ + { + "_readme": [ + "This file locks the dependencies of your project to a known state", +- "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", ++ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], +- "content-hash": "4db9a468fea5706b030e4b631a08b28a", ++ "content-hash": "57b9b4901479f79936d11b74f56ff761", + "packages": [ + { + "name": "container-interop/container-interop", +@@ -2769,20 +2769,21 @@ + }, + { + "name": "sensiolabs/security-checker", +- "version": "v4.1.8", ++ "version": "v5.0.3", + "source": { + "type": "git", + "url": "https://github.com/sensiolabs/security-checker.git", +- "reference": "dc270d5fec418cc6ac983671dba5d80ffaffb142" ++ "reference": "46be3f58adac13084497961e10eed9a7fb4d44d1" + }, + "dist": { + "type": "zip", +- "url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/dc270d5fec418cc6ac983671dba5d80ffaffb142", +- "reference": "dc270d5fec418cc6ac983671dba5d80ffaffb142", ++ "url": "https://api.github.com/repos/sensiolabs/security-checker/zipball/46be3f58adac13084497961e10eed9a7fb4d44d1", ++ "reference": "46be3f58adac13084497961e10eed9a7fb4d44d1", + "shasum": "" + }, + "require": { + "composer/ca-bundle": "^1.0", ++ "php": ">=5.5.9", + "symfony/console": "~2.7|~3.0|~4.0" + }, + "bin": [ +@@ -2791,12 +2792,12 @@ + "type": "library", + "extra": { + "branch-alias": { +- "dev-master": "4.1-dev" ++ "dev-master": "5.0-dev" + } + }, + "autoload": { +- "psr-0": { +- "SensioLabs\\Security": "" ++ "psr-4": { ++ "SensioLabs\\Security\\": "SensioLabs/Security" + } + }, + "notification-url": "https://packagist.org/downloads/", +@@ -2810,7 +2811,7 @@ + } + ], + "description": "A security checker for your composer.lock", +- "time": "2018-02-28T22:10:01+00:00" ++ "time": "2018-12-19T17:14:59+00:00" + }, + { + "name": "squizlabs/php_codesniffer", + +From 150a94fc71230ca04fc00e2f2b6c40936cb3c060 Mon Sep 17 00:00:00 2001 +From: Frederico Gendorf <fred@fldevws045> +Date: Fri, 15 Mar 2019 11:50:29 -0300 +Subject: [PATCH 09/10] Fix user image display and upload; fixes #5604 + +--- + front/document.send.php | 2 +- + inc/user.class.php | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/front/document.send.php b/front/document.send.php +index d80ab14aad..87a7db6298 100644 +--- a/front/document.send.php ++++ b/front/document.send.php +@@ -69,7 +69,7 @@ + } + + if ($splitter[0] == "_pictures") { +- if (Document::isImage($_GET['file'])) { ++ if (Document::isImage(GLPI_DOC_DIR."/".$_GET['file'])) { + $send = true; + } + } +diff --git a/inc/user.class.php b/inc/user.class.php +index fdc9d8b0ac..67bfc71496 100644 +--- a/inc/user.class.php ++++ b/inc/user.class.php +@@ -735,7 +735,7 @@ function prepareInputForUpdate($input) { + $picture_path = GLPI_PICTURE_DIR . "/$sub/${filename}.$extension"; + self::dropPictureFiles($filename.".".$extension); + +- if (Document::isImage($input["_picture"]) ++ if (Document::isImage($fullpath) + && Document::renameForce($fullpath, $picture_path)) { + Session::addMessageAfterRedirect(__('The file is valid. Upload is successful.')); + // For display + +From 9ef29babf8ae57986b2f3c1480a07c4608599a64 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?C=C3=A9dric=20Anne?= <cedric.anne@gmail.com> +Date: Fri, 22 Mar 2019 11:05:24 +0100 +Subject: [PATCH 10/10] Fix escaping of optgroups in dropdowns; fixes #5646 + +--- + js/common.js | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/js/common.js b/js/common.js +index 15cf04b200..e083b3970e 100644 +--- a/js/common.js ++++ b/js/common.js +@@ -958,11 +958,13 @@ var templateResult = function(result) { + var text = result.text; + if (text.indexOf('>') !== -1 || text.indexOf('<') !== -1) { + // escape text, if it contains chevrons (can already be escaped prior to this point :/) +- text = jQuery.fn.select2.defaults.defaults.escapeMarkup(result.text); ++ text = jQuery.fn.select2.defaults.defaults.escapeMarkup(text); + }; + + if (!result.id) { +- return text; ++ // If result has no id, then it is used as an optgroup and is not used for matches ++ _elt.html(text); ++ return _elt; + } + + var _term = query.term || ''; diff --git a/glpi-security2.patch b/glpi-security2.patch new file mode 100644 index 0000000..254c47a --- /dev/null +++ b/glpi-security2.patch @@ -0,0 +1,292 @@ +From 9cd45a1ec1932189fc5295e0f9978b36ab5eecaa Mon Sep 17 00:00:00 2001 +From: Remi Collet <remi@remirepo.net> +Date: Wed, 27 Mar 2019 14:55:25 +0100 +Subject: [PATCH] Fix/cookie auth (#5562) * prevent timed attack * add new + field for storing cookie token and reverse the verification (we store the + hash on our side and not client side) + +Backported from 9.4 26900a5e53a5ad347d20a947eb5f7e2b447fef9f + +Check cookie validity on glpi side + +Backported from 9.4 a3ab29c77c6fc7a45a7b0ef71c4442aee62acda6 + +Hack for DB Schema + +As 9.3.3 use dbschema 9.3.2, we can switch to 9.3.3 +Migration detection use dbversion, so will be raised +Script execution use version, which allow to keep it unchanged +More 9.4 is aware of 9.3.3 (not of 9.4) +--- + inc/auth.class.php | 19 ++++------- + inc/define.php | 2 +- + inc/update.class.php | 7 +++- + inc/user.class.php | 64 ++++++++++++++++++++++++++++++------ + install/mysql/glpi-empty.sql | 10 +++--- + install/update_932_933.php | 63 +++++++++++++++++++++++++++++++++++ + 6 files changed, 136 insertions(+), 29 deletions(-) + create mode 100644 install/update_932_933.php + +diff --git a/inc/auth.class.php b/inc/auth.class.php +index 707d7ab31..67d361653 100644 +--- a/inc/auth.class.php ++++ b/inc/auth.class.php +@@ -500,11 +500,11 @@ class Auth extends CommonGLPI { + if (count($data) === 2) { + list ($cookie_id, $cookie_token) = $data; + +- $token = User::getToken($cookie_id, 'personal_token'); ++ $user = new User(); ++ $user->getFromDB($cookie_id); ++ $hash = $user->getAuthToken('cookie_token'); + +- if ($token !== false && Auth::checkPassword($token, $cookie_token)) { +- $user = new User(); +- $user->getFromDB($cookie_id); //true if $token is not false ++ if (Auth::checkPassword($cookie_token, $hash)) { + $this->user->fields['name'] = $user->fields['name']; + return true; + } else { +@@ -848,12 +848,7 @@ class Auth extends CommonGLPI { + } + + if ($this->auth_succeded && $CFG_GLPI['login_remember_time'] > 0 && $remember_me) { +- $token = false; +- if (!empty($this->user->fields['personal_token'])) { +- $token = $this->user->fields['personal_token']; +- } else { +- $token = User::getToken($this->user->fields['id'], 'personal_token'); +- } ++ $token = $this->user->getAuthToken('cookie_token', true); + + if ($token) { + //Cookie name (Allow multiple GLPI) +@@ -861,11 +856,9 @@ class Auth extends CommonGLPI { + //Cookie session path + $cookie_path = ini_get('session.cookie_path'); + +- $hash = Auth::getPasswordHash($token); +- + $data = json_encode([ + $this->user->fields['id'], +- $hash, ++ $token, + ]); + + //Send cookie to browser +diff --git a/inc/define.php b/inc/define.php +index 78125529e..22830bc05 100644 +--- a/inc/define.php ++++ b/inc/define.php +@@ -41,7 +41,7 @@ if (substr(GLPI_VERSION, -4) === '-dev') { + ); + } else { + //for stable version +- define("GLPI_SCHEMA_VERSION", '9.3.2'); ++ define("GLPI_SCHEMA_VERSION", '9.3.3'); + } + define('GLPI_MIN_PHP', '5.6.0'); // Must also be changed in top of index.php + define('GLPI_YEAR', '2018'); +diff --git a/inc/update.class.php b/inc/update.class.php +index fec2271c0..e3da3c9f0 100644 +--- a/inc/update.class.php ++++ b/inc/update.class.php +@@ -431,7 +431,12 @@ class Update extends CommonGLPI { + case "9.3.1": + include_once "{$updir}update_931_932.php"; + update931to932(); +- break; ++ ++ case "9.3.2": ++ case "9.3.3": ++ // post 9.3.3 ++ include_once "{$updir}update_932_933.php"; ++ update932to933(); + + case GLPI_VERSION: + case GLPI_SCHEMA_VERSION: +diff --git a/inc/user.class.php b/inc/user.class.php +index 67bfc7149..d4139edfa 100644 +--- a/inc/user.class.php ++++ b/inc/user.class.php +@@ -4595,26 +4595,70 @@ class User extends CommonDBTM { + } + + +- /** ++ /** ++ * Get token of a user. If it does not exists then generate it. ++ * ++ * @since 9.4 ++ * ++ * @param string $field the field storing the token ++ * @param boolean $force_new force generation of a new token ++ * ++ * @return string|false token or false in case of error ++ */ ++ public function getAuthToken($field = 'personal_token', $force_new = false) { ++ global $CFG_GLPI; ++ ++ if ($this->isNewItem()) { ++ return false; ++ } ++ ++ // check date validity for cookie token ++ $outdated = false; ++ if ($field === 'cookie_token') { ++ $date_create = new DateTime($this->fields[$field."_date"]); ++ $date_expir = $date_create->add(new DateInterval('PT'.$CFG_GLPI["login_remember_time"].'S')); ++ ++ if ($date_expir < new DateTime()) { ++ $outdated = true; ++ } ++ } ++ ++ // token exists, is not oudated, and we may use it ++ if (!empty($this->fields[$field]) && !$force_new && !$outdated) { ++ return $this->fields[$field]; ++ } ++ ++ // else get a new token ++ $token = self::getUniqueToken($field); ++ ++ // for cookie token, we need to store it hashed ++ $hash = $token; ++ if ($field === 'cookie_token') { ++ $hash = Auth::getPasswordHash($token); ++ } ++ ++ // save this token in db ++ $this->update(['id' => $this->getID(), ++ $field => $hash, ++ $field . "_date" => $_SESSION['glpi_currenttime']]); ++ ++ return $token; ++ } ++ ++/** + * Get token of a user. If not exists generate it. + * + * @param integer $ID User ID + * @param string $field Field storing the token ++ * @param boolean $force_new force generation of a new token + * + * @return string|boolean User token, false if user does not exist + */ +- static function getToken($ID, $field = 'personal_token') { ++ static function getToken($ID, $field = 'personal_token', $force_new = false) { + + $user = new self(); + if ($user->getFromDB($ID)) { +- if (!empty($user->fields[$field])) { +- return $user->fields[$field]; +- } +- $token = self::getUniqueToken($field); +- $user->update(['id' => $user->getID(), +- $field => $token, +- $field . "_date" => $_SESSION['glpi_currenttime']]); +- return $user->fields[$field]; ++ return $user->getAuthToken($field, $force_new); + } + + return false; +diff --git a/install/mysql/glpi-empty.sql b/install/mysql/glpi-empty.sql +index abfe14600..14d6976c9 100644 +--- a/install/mysql/glpi-empty.sql ++++ b/install/mysql/glpi-empty.sql +@@ -8850,6 +8850,8 @@ CREATE TABLE `glpi_users` ( + `personal_token_date` datetime DEFAULT NULL, + `api_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, + `api_token_date` datetime DEFAULT NULL, ++ `cookie_token` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, ++ `cookie_token_date` datetime DEFAULT NULL, + `display_count_on_home` int(11) DEFAULT NULL, + `notification_to_myself` tinyint(1) DEFAULT NULL, + `duedateok_color` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, +@@ -8900,10 +8902,10 @@ CREATE TABLE `glpi_users` ( + KEY `sync_field` (`sync_field`) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; + +-INSERT INTO `glpi_users` VALUES ('2','glpi','$2y$10$rXXzbc2ShaiCldwkw4AZL.n.9QSH7c0c9XJAyyjrbL9BwmWditAYm','','','','',NULL,'0',NULL,'0','20','1',NULL,'0','1','2014-06-18 08:02:24','2014-06-18 08:02:24',NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); +-INSERT INTO `glpi_users` VALUES ('3','post-only','$2y$10$dTMar1F3ef5X/H1IjX9gYOjQWBR1K4bERGf4/oTPxFtJE/c3vXILm','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); +-INSERT INTO `glpi_users` VALUES ('4','tech','$2y$10$.xEgErizkp6Az0z.DHyoeOoenuh0RcsX4JapBk2JMD6VI17KtB1lO','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); +-INSERT INTO `glpi_users` VALUES ('5','normal','$2y$10$Z6doq4zVHkSPZFbPeXTCluN1Q/r0ryZ3ZsSJncJqkN3.8cRiN0NV.','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); ++INSERT INTO `glpi_users` VALUES ('2','glpi','$2y$10$rXXzbc2ShaiCldwkw4AZL.n.9QSH7c0c9XJAyyjrbL9BwmWditAYm','','','','',NULL,'0',NULL,'0','20','1',NULL,'0','1','2014-06-18 08:02:24','2014-06-18 08:02:24',NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); ++INSERT INTO `glpi_users` VALUES ('3','post-only','$2y$10$dTMar1F3ef5X/H1IjX9gYOjQWBR1K4bERGf4/oTPxFtJE/c3vXILm','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); ++INSERT INTO `glpi_users` VALUES ('4','tech','$2y$10$.xEgErizkp6Az0z.DHyoeOoenuh0RcsX4JapBk2JMD6VI17KtB1lO','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); ++INSERT INTO `glpi_users` VALUES ('5','normal','$2y$10$Z6doq4zVHkSPZFbPeXTCluN1Q/r0ryZ3ZsSJncJqkN3.8cRiN0NV.','','','','',NULL,'0','en_GB','0','20','1',NULL,'0','1',NULL,NULL,NULL,'0','0','0','0','0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,'0',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,0,'',NULL); + + ### Dump table glpi_usertitles + +diff --git a/install/update_932_933.php b/install/update_932_933.php +new file mode 100644 +index 000000000..240c5cb00 +--- /dev/null ++++ b/install/update_932_933.php +@@ -0,0 +1,63 @@ ++<?php ++/** ++ * --------------------------------------------------------------------- ++ * GLPI - Gestionnaire Libre de Parc Informatique ++ * Copyright (C) 2015-2017 Teclib' and contributors. ++ * ++ * http://glpi-project.org ++ * ++ * based on GLPI - Gestionnaire Libre de Parc Informatique ++ * Copyright (C) 2003-2014 by the INDEPNET Development Team. ++ * ++ * --------------------------------------------------------------------- ++ * ++ * LICENSE ++ * ++ * This file is part of GLPI. ++ * ++ * GLPI is free software; you can redistribute it and/or modify ++ * it under the terms of the GNU General Public License as published by ++ * the Free Software Foundation; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * GLPI is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ * You should have received a copy of the GNU General Public License ++ * along with GLPI. If not, see <http://www.gnu.org/licenses/>. ++ * --------------------------------------------------------------------- ++ */ ++ ++/** @file ++* @brief ++*/ ++ ++/** ++ * Update from 9.3.2 to 9.3.3 (DB schema version, introduced post 9.3.3) ++ * ++ * @return bool for success (will die for most error) ++**/ ++function update932to933() { ++ global $DB, $migration, $CFG_GLPI; ++ ++ $current_config = Config::getConfigurationValues('core'); ++ $updateresult = true; ++ $ADDTODISPLAYPREF = []; ++ ++ //TRANS: %s is the number of new version ++ $migration->displayTitle(sprintf(__('Update to %s'), '9.3.3')); ++ $migration->setVersion('9.3.3'); ++ ++ // Create a dedicated token for rememberme process ++ if (!$DB->fieldExists('glpi_users', 'cookie_token')) { ++ $migration->addField('glpi_users', 'cookie_token', 'string', ['after' => 'api_token_date']); ++ $migration->addField('glpi_users', 'cookie_token_date', 'datetime', ['after' => 'cookie_token']); ++ } ++ ++ // ************ Keep it at the end ************** ++ $migration->executeMigration(); ++ ++ return $updateresult; ++} +-- +2.20.1 + @@ -1,6 +1,6 @@ # Fedora/remirepo spec file for glpi # -# Copyright (c) 2007-2018 Remi Collet +# Copyright (c) 2007-2019 Remi Collet # License: CC-BY-SA # http://creativecommons.org/licenses/by-sa/4.0/ # @@ -56,7 +56,7 @@ Name: %{gh_project} #global upstream_prever RC2 # use 9.3.0~RC2 < 9.3 (for plugin compatibility check) Version: %{upstream_version}%{?upstream_prever:~%{upstream_prever}} -Release: 1%{?dist} +Release: 2%{?dist} Summary: Free IT asset management software Summary(fr): Gestion Libre de Parc Informatique @@ -76,6 +76,12 @@ Source6: %{name}-minify.php # Override PHP configuration for php-fpm Source7: %{name}-user.ini +# Security patches backported from 9.4 +# https://github.com/glpi-project/glpi/pull/5606 merged +Patch1: glpi-security1.patch +# Backports +Patch2: glpi-security2.patch + BuildArch: noarch BuildRequires: gettext BuildRequires: php-cli @@ -308,6 +314,9 @@ techniciens grâce à une maintenance plus cohérente. %prep %setup -q -n %{name}-%{gh_commit} +%patch1 -p1 -b .secfix +%patch2 -p1 -b .secfix +find . -name \*.secfix -delete -print grep %{upstream_version} inc/define.php @@ -595,6 +604,15 @@ fi %changelog +* Wed Mar 27 2019 Remi Collet <remi@remirepo.net> - 9.3.3-2 +- add security fix backported from 9.4.1: + [security] Bad chevrons rendering on dropdowns + [security] Iframe and forms are rendered in rich text contents + [security] Type juggling authentication bypass + [security] Malicious images upload + [security] Password token date was not reset + [security] Prevent timed attack and enforce cookie security + * Tue Nov 27 2018 Remi Collet <remi@remirepo.net> - 9.3.3-1 - update to 9.3.3 |