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 | 
