CVE-2020-11060 (published 2020-05-12T20:15Z)

In GLPI before 9.4.6, an attacker can execute system commands by abusing the backup functionality. Theoretically, this vulnerability can be exploited by an attacker without a valid account by using a CSRF. Due to the difficulty of the exploitation, the attack is only conceivable by an account having Maintenance privileges and the right to add WIFI networks. This is fixed in version 9.4.6.

Severity: HIGH
CVSS v2 base score: 9.0 (AV:N/AC:L/Au:S/C:C/I:C/A:C)
CVSS v3 base score: 8.8, HIGH (CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H)

Weakness information:
cwe_id: CWE-352
cwe_name: Cross-Site Request Forgery (CSRF)
description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
extended_description: When a web server is designed to receive a request from a client without any mechanism for verifying that it was intentionally sent, then it might be possible for an attacker to trick a client into making an unintentional request to the web server which will be treated as an authentic request. This can be done via a URL, image load, XMLHttpRequest, etc. and can result in exposure of data or unintended code execution.
         

Fix information:
repo_url: https://github.com/glpi-project/glpi
commit_details: repo_url: https://github.com/glpi-project/glpi
author: Johan Cwiklinski
author_date: 2020-04-28 08:08:02+02:00
msg: Drop xml backup; check new versions from config

closes #7182
repository: repo_url: https://github.com/glpi-project/glpi
repo_name: glpi-project/glpi
description: GLPI is a Free Asset and IT Management Software package, Data center management, ITIL Service Desk, licenses tracking and software auditing.
repo_language: PHP
owner: glpi-project
file_changes: filename: backup.php
change_type: ModificationType.DELETE
diff: @@ -1,700 +0,0 @@
-<?php
-/**
- * ---------------------------------------------------------------------
- * GLPI - Gestionnaire Libre de Parc Informatique
- * Copyright (C) 2015-2018 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/>.
- * ---------------------------------------------------------------------
- */
-
-include ('../inc/includes.php');
-
-if (isset($_POST['check_version'])) {
-   Session::checkRight('backup', Backup::CHECKUPDATE);
-   Toolbox::checkNewVersionAvailable(0, true);
-   Html::back();
-}
-
-Session::checkRight("backup", READ);
-
-Html::header(__('Maintenance'), $_SERVER['PHP_SELF'], "admin", "backup");
-
-$max_time = min(get_cfg_var("max_execution_time"), get_cfg_var("max_input_time"));
-
-if ($max_time == 0) {
-   $defaulttimeout  = 60;
-   $defaultrowlimit = 5;
-
-} else if ($max_time > 5) {
-   $defaulttimeout  = $max_time-2;
-   $defaultrowlimit = 5;
-
-} else {
-   $defaulttimeout  = max(1, $max_time-2);
-   $defaultrowlimit = 2;
-}
-
-
-/**
- * Generate an XML backup file of the database
- * @global DB $DB
- */
-function xmlbackup() {
-   global $CFG_GLPI, $DB;
-
-   //on parcoure la DB et on liste tous les noms des tables dans $table
-   //on incremente $query[] de "select * from $table"  pour chaque occurence de $table
-
-   $result = $DB->listTables();
-   $i      = 0;
-   while ($line = $result->next()) {
-      $table = $line['TABLE_NAME'];
-
-      $query[$i] = "SELECT *
-                    FROM `$table`";
-      $i++;
-   }
-
-   // Filename
-   $time_file = date("Y-m-d-H-i");
-   $filename = GLPI_DUMP_DIR . "/glpi-backup-" . GLPI_VERSION . "-$time_file.xml";
-
-   $A = new XML();
-
-   // Your query
-   $A->SqlString = $query;
-
-   //File path
-   $A->FilePath = $filename;
-
-   // Define layout type
-   $A->Type = 4;
-
-   // Generate the XML file
-   $A->DoXML();
-
-   // In case of error, display it
-   if ($A->IsError == 1) {
-      printf(__('ERROR:'), $A->ErrorString);
-   }
-}
-
-/**
- * Init time to computer time spend
- * @global type $TPSDEB
- * @global int $TPSCOUR
- */
-function init_time() {
-   global $TPSDEB, $TPSCOUR;
-
-   list($usec,$sec) = explode(" ", microtime());
-   $TPSDEB          = $sec;
-   $TPSCOUR         = 0;
-}
-
-/**
- * Get current time
- * @global type $TPSDEB
- * @global type $TPSCOUR
- */
-function current_time() {
-   global $TPSDEB, $TPSCOUR;
-
-   list($usec,$sec) = explode(" ", microtime());
-   $TPSFIN          = $sec;
-   if (round($TPSFIN-$TPSDEB, 1) >= $TPSCOUR+1) {//une seconde de plus
-      $TPSCOUR = round($TPSFIN-$TPSDEB, 1);
-   }
-}
-
-/**
- * Get data of a table
- * @param DB $DB
- * @param string $table table name
- * @param integer $from FROM xxx
- * @param integer $limit LIMIT xxx
- * @return string SQL query "INSERT INTO..."
- */
-function get_content($DB, $table, $from, $limit) {
-
-   $content = "";
-
-   $iterator = $DB->request($table, ['START' => $from, 'LIMIT' => $limit]);
-
-   if ($iterator->count()) {
-
-      while ($row = $iterator->next()) {
-         $insert = "INSERT INTO `$table` VALUES (";
-
-         foreach ($row as $field_key => $field_val) {
-            if (is_null($field_val)) {
-               $insert .= "NULL,";
-            } else if ($field_val != "") {
-               $insert .= "'" . addslashes($field_val) . "',";
-            } else {
-               $insert .= "'',";
-            }
-         }
-         $insert = preg_replace("/,$/", "", $insert);
-         $insert .= ");\n";
-         $content .= $insert;
-      }
-   }
-   return $content;
-}
-
-/**  Get structure of a table
- *
- * @param $DB     DB object
- * @param $table  table name
-**/
-function get_def($DB, $table) {
-
-   $def  = "### Dump table $table\n\n";
-   $def .= "DROP TABLE IF EXISTS `$table`;\n";
-
-   $query  = "SHOW CREATE TABLE `$table`";
-   $result = $DB->query($query);
-   $DB->query("SET SESSION sql_quote_show_create = 1");
-   $row = $DB->fetch_row($result);
-
-   $def .= preg_replace("/AUTO_INCREMENT=\w+/i", "", $row[1]);
-   $def .= ";";
-   return $def."\n\n";
-}
-
-
-/**  Restore a mysql dump
- *
- * @param $DB        DB object
- * @param $dumpFile  dump file
- * @param $duree     max delay before refresh
-**/
-function restoreMySqlDump($DB, $dumpFile, $duree) {
-   global $DB, $TPSCOUR, $offset, $cpt;
-
-   // $dumpFile, fichier source
-   // $duree=timeout pour changement de page (-1 = aucun)
-
-   // Desactivation pour empecher les addslashes au niveau de la creation des tables
-   // En plus, au niveau du dump on considere qu'on est bon
-   // set_magic_quotes_runtime(0);
-
-   if (!file_exists($dumpFile)) {
-      echo sprintf(__('File %s not found.'), $dumpFile)."<br>";
-      return false;
-   }
-   if (substr($dumpFile, -2) == "gz") {
-      $fileHandle = gzopen($dumpFile, "rb");
-   } else {
-      $fileHandle = fopen($dumpFile, "rb");
-   }
-
-   if (!$fileHandle) {
-      //TRASN: %s is the name of the file
-      echo sprintf(__('Unauthorized access to the file %s'), $dumpFile)."<br>";
-      return false;
-   }
-
-   if ($offset != 0) {
-      if (substr($dumpFile, -2) == "gz") {
-         if (gzseek($fileHandle, $offset, SEEK_SET) != 0) { //erreur
-            //TRANS: %s is the number of the byte
-            printf(__("Unable to find the byte %s"), Html::formatNumber($offset, false, 0));
-            echo "<br>";
-            return false;
-         }
-      } else {
-         if (fseek($fileHandle, $offset, SEEK_SET) != 0) { //erreur
-            //TRANS: %s is the number of the byte
-            printf(__("Unable to find the byte %s"), Html::formatNumber($offset, false, 0));
-            echo "<br>";
-            return false;
-         }
-      }
-      Html::glpi_flush();
-   }
-
-   $formattedQuery = "";
-
-   if (substr($dumpFile, -2) == "gz") {
-      while (!gzeof($fileHandle)) {
-         current_time();
-         if (($duree > 0)
-             && ($TPSCOUR >= $duree)) { //on atteint la fin du temps imparti
-            return true;
-         }
-
-         // specify read length to be able to read long lines
-         $buffer = gzgets($fileHandle, 102400);
-
-         // do not strip comments due to problems when # in begin of a data line
-         $formattedQuery .= $buffer;
-
-         if (substr(rtrim($formattedQuery), -1) == ";") {
-            // Do not use the $DB->query
-            if ($DB->query($formattedQuery)) { //if no success continue to concatenate
-               $offset         = gztell($fileHandle);
-               $formattedQuery = "";
-               $cpt++;
-            }
-         }
-      }
-   } else {
-      while (!feof($fileHandle)) {
-         current_time();
-         if (($duree > 0)
-               && ($TPSCOUR >= $duree)) { //on atteint la fin du temps imparti
-            return true;
-         }
-
-         // specify read length to be able to read long lines
-         $buffer = fgets($fileHandle, 102400);
-
-         // do not strip comments due to problems when # in begin of a data line
-         $formattedQuery .= $buffer;
-
-         if (substr(rtrim($formattedQuery), -1) == ";") {
-            // Do not use the $DB->query
-            if ($DB->query($formattedQuery)) { //if no success continue to concatenate
-               $offset         = ftell($fileHandle);
-               $formattedQuery = "";
-               $cpt++;
-            }
-         }
-      }
-   }
-
-   if ($DB->error) {
-      echo "<hr>";
-      //TRANS: %s is the SQL query which generates the error
-      printf(__("SQL error starting from %s"), "[$formattedQuery]");
-      echo "<br>".$DB->error()."<hr>";
-   }
-
-   if (substr($dumpFile, -2) == "gz") {
-      gzclose($fileHandle);
-   } else {
-      fclose($fileHandle);
-   }
-   $offset = -1;
-   return true;
-}
-
-
-/**  Backup a glpi DB
- *
- * @param $DB        DB object
- * @param $dumpFile  dump file
- * @param $duree     max delay before refresh
- * @param $rowlimit  rowlimit to backup in one time
-**/
-function backupMySql($DB, $dumpFile, $duree, $rowlimit) {
-   global $TPSCOUR, $offsettable, $offsetrow, $cpt;
-
-   // $dumpFile, fichier source
-   // $duree=timeout pour changement de page (-1 = aucun)
-
-   if (function_exists('gzopen')) {
-      $fileHandle = gzopen($dumpFile, "a");
-   } else {
-      $fileHandle = gzopen64($dumpFile, "a");
-   }
-
-   if (!$fileHandle) {
-      //TRANS: %s is the name of the file
-      echo sprintf(__('Unauthorized access to the file %s'), $dumpFile)."<br>";
-      return false;
-   }
-
-   if ($offsettable == 0 && $offsetrow == -1) {
-      $time_file = date("Y-m-d-H-i");
-      $cur_time  = date("Y-m-d H:i");
-      $todump    = "#GLPI Dump database on $cur_time\n";
-      gzwrite ($fileHandle, $todump);
-   }
-
-   $result = $DB->listTables();
-   $numtab = 0;
-   while ($t = $result->next()) {
-      $tables[$numtab] = $t['TABLE_NAME'];
-      $numtab++;
-   }
-
-   for (; $offsettable<$numtab; $offsettable++) {
-      // Dump de la structure table
-      if ($offsetrow == -1) {
-         $todump = "\n".get_def($DB, $tables[$offsettable]);
-         gzwrite ($fileHandle, $todump);
-         $offsetrow++;
-         $cpt++;
-      }
-      current_time();
-      if (($duree > 0)
-          && ($TPSCOUR >= $duree)) { //on atteint la fin du temps imparti
-         return true;
-      }
-      $fin = 0;
-      while (!$fin) {
-         $todump    = get_content($DB, $tables[$offsettable], $offsetrow, $rowlimit);
-         $rowtodump = substr_count($todump, "INSERT INTO");
-
-         if ($rowtodump > 0) {
-            gzwrite ($fileHandle, $todump);
-            $cpt       += $rowtodump;
-            $offsetrow += $rowlimit;
-            if ($rowtodump<$rowlimit) {
-               $fin = 1;
-            }
-            current_time();
-            if (($duree > 0)
-                && ($TPSCOUR >= $duree)) { //on atteint la fin du temps imparti
-               return true;
-            }
-
-         } else {
-            $fin       = 1;
-            $offsetrow = -1;
-         }
-      }
-
-      if ($fin) {
-         $offsetrow = -1;
-      }
-      current_time();
-      if (($duree > 0)
-          && ($TPSCOUR >= $duree)) { //on atteint la fin du temps imparti
-         return true;
-      }
-   }
-
-   if ($DB->error()) {
-      echo "<hr>";
-      //TRANS: %s is the SQL query which generates the error
-      printf(__("SQL error starting from %s"), "[$formattedQuery]");
-      echo "<br>".$DB->error()."<hr>";
-   }
-   $offsettable = -1;
-   gzclose($fileHandle);
-   return true;
-}
-
-
-// #################" DUMP sql#################################
-
-if (isset($_GET["dump"]) && $_GET["dump"] != "") {
-   $time_file = date("Y-m-d-H-i");
-   $cur_time  = date("Y-m-d H:i");
-   $filename  = GLPI_DUMP_DIR . "/glpi-backup-".GLPI_VERSION."-$time_file.sql.gz";
-
-   if (!isset($_GET["duree"]) && is_file($filename)) {
-      echo "<div class='center'>".__('The file already exists')."</div>";
-
-   } else {
-      init_time(); //initialise le temps
-      //debut de fichier
-
-      if (!isset($_GET["offsettable"])) {
-         $offsettable = 0;
-      } else {
-         $offsettable = $_GET["offsettable"];
-      }
-
-      //debut de fichier
-      if (!isset($_GET["offsetrow"])) {
-         $offsetrow = -1;
-      } else {
-         $offsetrow = $_GET["offsetrow"];
-      }
-
-      //timeout de 5 secondes par defaut, -1 pour utiliser sans timeout
-      if (!isset($_GET["duree"])) {
-         $duree = $defaulttimeout;
-      } else {
-         $duree = $_GET["duree"];
-      }
-
-      //Limite de lignes a dumper a chaque fois
-      if (!isset($_GET["rowlimit"])) {
-         $rowlimit = $defaultrowlimit;
-      } else {
-         $rowlimit = $_GET["rowlimit"];
-      }
-
-      //si le nom du fichier n'est pas en parametre le mettre ici
-      if (!isset($_GET["fichier"])) {
-         $fichier = $filename;
-      } else {
-         $fichier = $_GET["fichier"];
-      }
-
-      $tot = $DB->listTables()->count();
-      if (isset($offsettable)) {
-         if ($offsettable >= 0) {
-            $percent = min(100, round(100*$offsettable/$tot, 0));
-         } else {
-            $percent = 100;
-         }
-      } else {
-         $percent = 0;
-      }
-
-      if ($percent >= 0) {
-         Html::displayProgressBar(400, $percent);
-         echo '<br>';
-      }
-
-      if ($offsettable >= 0) {
-         if (backupMySql($DB, $fichier, $duree, $rowlimit)) {
-            echo "<div class='center spaced'>".
-                 "<a href=\"backup.php?dump=1&duree=$duree&rowlimit=$rowlimit&offsetrow=".
-                    "$offsetrow&offsettable=$offsettable&cpt=$cpt&fichier=$fichier\">".
-                    __('Automatic redirection, else click')."</a>";
-            echo "<script type='text/javascript'>" .
-                "window.location=\"backup.php?dump=1&duree=$duree&rowlimit=".
-                     "$rowlimit&offsetrow=$offsetrow&offsettable=$offsettable&cpt=$cpt&fichier=".
-                     "$fichier\";</script></div>";
-            Html::glpi_flush();
-            exit;
-         }
-      }
-   }
-}
-
-
-// ##############################   fin dump sql########################""""
-
-
-// ################################## dump XML #############################
-
-if (isset($_GET["xmlnow"]) && ($_GET["xmlnow"] != "")) {
-   xmlbackup();
-}
-
-// ################################## fin dump XML #############################
-
-if (isset($_GET["file"]) && ($_GET["file"] != "") && is_file(GLPI_DUMP_DIR . "/" . $_GET["file"])) {
-   $filepath = realpath(GLPI_DUMP_DIR . "/" . $_GET['file']);
-   if (is_file($filepath) && Toolbox::startsWith($filepath, GLPI_DUMP_DIR)) {
-      $_SESSION['TRY_OLD_CONFIG_FIRST'] = true;
-      init_time(); //initialise le temps
-
-      //debut de fichier
-      if (!isset($_GET["offset"])) {
-         $offset = 0;
-      } else {
-         $offset = $_GET["offset"];
-      }
-
-      //timeout de 5 secondes par defaut, -1 pour utiliser sans timeout
-      if (!isset($_GET["duree"])) {
-         $duree = $defaulttimeout;
-      } else {
-         $duree = $_GET["duree"];
-      }
-
-      $fsize = filesize($filepath);
-      if (isset($offset)) {
-         if ($offset == -1) {
-            $percent = 100;
-         } else {
-            $percent = min(100, round(100*$offset/$fsize, 0));
-         }
-      } else {
-         $percent = 0;
-      }
-
-      if ($percent >= 0) {
-         Html::displayProgressBar(400, $percent);
-         echo '<br>';
-      }
-
-      if ($offset != -1) {
-         if (restoreMySqlDump($DB, $filepath, $duree)) {
-            echo "<div class='center'>".
-               "<a href=\"backup.php?file=".$_GET["file"]."&amp;duree=$duree&amp;offset=".
-                     "$offset&amp;cpt=$cpt&amp;donotcheckversion=1\">";
-            echo __('Automatic redirection, else click')."</a>";
-            echo "<script language='javascript' type='text/javascript'>".
-                  "window.location=\"backup.php?file=".
-                  $_GET["file"]."&duree=$duree&offset=$offset&cpt=$cpt&donotcheckversion=1\";".
-                  "</script></div>";
-            Html::glpi_flush();
-            exit;
-         }
-
-      } else {
-         // Compatiblity for old version for utf8 complete conversion
-         $cnf                = new Config();
-         $input['id']        = 1;
-         $input['utf8_conv'] = 1;
-         $cnf->update($input);
-      }
-   }
-}
-
-if (isset($_POST["delfile"])) {
-   if (isset($_POST['file']) && ($_POST["file"] != "")) {
-      $filepath = realpath(GLPI_DUMP_DIR . "/" . $_POST['file']);
-      if (is_file($filepath) && Toolbox::startsWith($filepath, GLPI_DUMP_DIR)) {
-         $filename = $_POST["file"];
-         unlink($filepath);
-         // TRANS: %s is a file name
-         echo "<div class ='center spaced'>".sprintf(__('%s deleted'), $filename)."</div>";
-      }
-   }
-}
-
-if (Session::haveRight('backup', Backup::CHECKUPDATE)) {
-   echo "<div class='center spaced'><table class='tab_glpi'>";
-   echo "<tr class='tab_bg_1'><td colspan='4' class='center b'>";
-   Html::showSimpleForm($_SERVER['PHP_SELF'], 'check_version',
-                        __('Check if a new version is available'));
-   echo "</td></tr></table></div>";
-}
-
-// Title backup
-echo "<div class='center'>";
-if (Session::haveRight('backup', CREATE)) {
-   echo "<table class='tab_glpi'><tr><td colspan='4'>";
-   echo "<div class='warning'><i class='fa fa-exclamation-triangle fa-5x'></i><ul><li>";
-   echo __('GLPI internal backup system is a helper for very small instances.');
-   echo "<br/>" . __('You should rather use a dedicated tool on your server.');
-   echo "</li></ul></div>";
-   echo "</td></tr><tr><td>";
-   echo "<i class='far fa-save fa-3x'></i>";
-         "</td>";
-   echo "<td><a class='vsubmit'
-              href=\"#\" ".HTML::addConfirmationOnAction(__('Backup the database?'),
-                                                         "window.location='".$CFG_GLPI["root_doc"].
-                                                           "/front/backup.php?dump=dump'").
-              ">".__('SQL Dump')."</a>&nbsp;</td>";
-   echo "<td><a class='vsubmit'
-              href=\"#\" ".HTML::addConfirmationOnAction(__('Backup the database?'),
-                                                         "window.location='".$CFG_GLPI["root_doc"].
-                                                           "/front/backup.php?xmlnow=xmlnow'").
-              ">".__('XML Dump')."</a>&nbsp;</td>";
-   echo "</tr></table>";
-}
-echo "<br><table class='tab_cadre' cellpadding='5'>".
-     "<tr class='center'>".
-     "<th><u><i>".__('File')."</i></u></th>".
-     "<th><u><i>".__('Size')."</i></u></th>".
-     "<th><u><i>".__('Date')."</i></u></th>".
-     "<th colspan='3'>&nbsp;</th>".
-     "</tr>";
-
-$dir   = opendir(GLPI_DUMP_DIR);
-$files = [];
-while ($file = readdir($dir)) {
-   if (($file != ".") && ($file != "..")
-       && (preg_match("/\.sql.gz$/i", $file)
-           || preg_match("/\.sql$/i", $file))) {
-
-      $files[$file] = filemtime(GLPI_DUMP_DIR . "/" . $file);
-   }
-}
-arsort($files);
-
-if (count($files)) {
-   foreach ($files as $file => $date) {
-      $taille_fic = filesize(GLPI_DUMP_DIR . "/" . $file);
-      echo "<tr class='tab_bg_2'><td>$file&nbsp;</td>".
-           "<td class='right'>".Toolbox::getSize($taille_fic)."</td>".
-           "<td>&nbsp;" . Html::convDateTime(date("Y-m-d H:i", $date)) . "</td>";
-      if (Session::haveRight('backup', PURGE)) {
-         echo "<td>&nbsp;";
-              //TRANS: %s is the filename
-              $string = sprintf(__('Delete the file %s?'), $file);
-              Html::showSimpleForm($_SERVER['PHP_SELF'], 'delfile',
-                                   _x('button', 'Delete permanently'),
-                                   ['file' => $file], '', '', $string);
-
-         echo "</td>";
-         echo "<td>&nbsp;";
-         // Multiple confirmation
-         $string   = [];
-         //TRANS: %s is the filename
-         $string[] = [sprintf(__('Replace the current database with the backup file %s?'),
-                                   $file)];
-         $string[] = [__('Warning, your actual database will be totaly overwriten by the database you want to restore !!!')];
-
-         echo "<a class='vsubmit' href=\"#\" ".HTML::addConfirmationOnAction($string,
-                                        "window.location='".$CFG_GLPI["root_doc"].
-                                        "/front/backup.php?file=$file&amp;donotcheckversion=1'").
-              ">".__('Restore')."</a>&nbsp;</td>";
-      }
-      if (Session::haveRight('backup', CREATE)) {
-         echo "<td>&nbsp;".
-              "<a class='vsubmit' href=\"document.send.php?file=_dumps/$file\">".__('Download').
-              "</a></td>";
-      }
-      echo "</tr>";
-   }
-}
-closedir($dir);
-
-$dir = opendir(GLPI_DUMP_DIR);
-unset($files);
-$files = [];
-
-while ($file = readdir($dir)) {
-   if (($file != ".") && ($file != "..")
-       && preg_match("/\.xml$/i", $file)) {
-
-      $files[$file] = filemtime(GLPI_DUMP_DIR . "/" . $file);
-   }
-}
-arsort($files);
-
-if (count($files)) {
-   foreach ($files as $file => $date) {
-      $taille_fic = filesize(GLPI_DUMP_DIR . "/" . $file);
-      echo "<tr class='tab_bg_1'><td colspan='6'><hr noshade></td></tr>".
-           "<tr class='tab_bg_2'><td>$file&nbsp;</td>".
-            "<td class='right'>".Toolbox::getSize($taille_fic)."</td>".
-            "<td>&nbsp;" . Html::convDateTime(date("Y-m-d H:i", $date)) . "</td>";
-      if (Session::haveRight('backup', PURGE)) {
-         echo "<td colspan=2>";
-         //TRANS: %s is the filename
-         $string = sprintf(__('Delete the file %s?'), $file);
-         Html::showSimpleForm($_SERVER['PHP_SELF'], 'delfile', _x('button', 'Delete permanently'),
-                              ['file' => $file], '', '', $string);
-         echo "</td>";
-      }
-      if (Session::haveRight('backup', CREATE)) {
-         echo "<td>&nbsp;<a class='vsubmit' href=\"document.send.php?file=_dumps/$file\">".
-                       __('Download')."</a></td>";
-      }
-      echo "</tr>";
-   }
-}
-closedir($dir);
-
-echo "</table>";
-echo "</div>";
-
-Html::footer();

programming_language: unknown
filename: config.form.php
change_type: ModificationType.MODIFY
diff: @@ -33,6 +33,13 @@
 include ('../inc/includes.php');
 Session::checkRight("config", READ);
 
+if (isset($_GET['check_version'])) {
+    Session::addMessageAfterRedirect(
+        Toolbox::checkNewVersionAvailable()
+    );
+    Html::back();
+}
+
 $config = new Config();
 $_POST['id'] = 1;
 if (!empty($_POST["update_auth"])) {

programming_language: PHP
filename: config.class.php
change_type: ModificationType.MODIFY
diff: @@ -1779,6 +1779,9 @@ class Config extends CommonDBTM {
 
       echo "<table class='tab_cadre_fixe'>";
       echo "<tr><th>". __('Information about system installation and configuration')."</th></tr>";
+      echo "<tr class='tab_bg_1'><td>";
+      echo "<a class='vsubmit' href='?check_version'>".__('Check if a new version is available')."</a>";
+      echo "</td></tr>";
 
        $oldlang = $_SESSION['glpilanguage'];
        // Keep this, for some function call which still use translation (ex showAllReplicateDelay)

programming_language: PHP
filename: updatecommand.class.php
change_type: ModificationType.MODIFY
diff: @@ -170,8 +170,8 @@ class UpdateCommand extends AbstractCommand implements ForceNoPluginsOptionComma
       } else if ($force) {
          // Replay last update script even if there is no schema change.
          // It can be used in dev environment when update script has been updated/fixed.
-         include_once(GLPI_ROOT . '/install/update_943_945.php');
-         update943to945();
+         include_once(GLPI_ROOT . '/install/update_945_946.php');
+         update945to946();
 
          $output->writeln('<info>' . __('Last migration replayed.') . '</info>');
       }

programming_language: PHP
filename: crontask.class.php
change_type: ModificationType.MODIFY
diff: @@ -1654,7 +1654,7 @@ class CronTask extends CommonDBTM{
    **/
    static function cronCheckUpdate($task) {
 
-      $result = Toolbox::checkNewVersionAvailable(1);
+      $result = Toolbox::checkNewVersionAvailable();
       $task->log($result);
 
       return 1;

programming_language: PHP
filename: html.class.php
change_type: ModificationType.MODIFY
diff: @@ -1414,7 +1414,7 @@ class Html {
 
       $menu['admin']['title']        = __('Administration');
       $menu['admin']['types']        = ['User', 'Group', 'Entity', 'Rule',
-                                             'Profile', 'QueuedNotification', 'Backup', 'Glpi\\Event'];
+                                             'Profile', 'QueuedNotification', 'Glpi\\Event'];
 
       $menu['config']['title']       = __('Setup');
       $menu['config']['types']       = ['CommonDropdown', 'CommonDevice', 'Notification',

programming_language: PHP
filename: profile.class.php
change_type: ModificationType.MODIFY
diff: @@ -1321,9 +1321,6 @@ class Profile extends CommonDBTM {
                       ['itemtype'  => 'QueuedNotification',
                             'label'     => __('Notification queue'),
                             'field'     => 'queuednotification'],
-                      ['itemtype'  => 'Backup',
-                            'label'     => __('Maintenance'),
-                            'field'     => 'backup'],
                       ['itemtype'  => 'Log',
                             'label'     => _n('Log', 'Logs', Session::getPluralNumber()),
                             'field'     => 'logs']];

programming_language: PHP
filename: toolbox.class.php
change_type: ModificationType.MODIFY
diff: @@ -1407,25 +1407,11 @@ class Toolbox {
    /**
     * Check if new version is available
     *
-    * @param $auto                  boolean: check done autically ? (if not display result)
-    *                                        (true by default)
-    * @param $messageafterredirect  boolean: use message after redirect instead of display
-    *                                        (false by default)
-    *
-    * @return string explaining the result
+    * @return string
    **/
-   static function checkNewVersionAvailable($auto = true, $messageafterredirect = false) {
+   static function checkNewVersionAvailable() {
       global $CFG_GLPI;
 
-      if (!$auto
-          && !Session::haveRight('backup', Backup::CHECKUPDATE)) {
-         return false;
-      }
-
-      if (!$auto && !$messageafterredirect) {
-         echo "<br>";
-      }
-
       //parse github releases (get last version number)
       $error = "";
       $json_gh_releases = self::getURLContent("https://api.github.com/repos/glpi-project/glpi/releases", $error);
@@ -1440,56 +1426,13 @@ class Toolbox {
       $latest_version = array_pop($released_tags);
 
       if (strlen(trim($latest_version)) == 0) {
-         if (!$auto) {
-            if ($messageafterredirect) {
-               Session::addMessageAfterRedirect($error, true, ERROR);
-            } else {
-               echo "<div class='center'>$error</div>";
-            }
-         } else {
-            return $error;
-         }
-
+         return $error;
       } else {
          if (version_compare($CFG_GLPI["version"], $latest_version, '<')) {
             Config::setConfigurationValues('core', ['founded_new_version' => $latest_version]);
-
-            if (!$auto) {
-               if ($messageafterredirect) {
-                  Session::addMessageAfterRedirect(sprintf(__('A new version is available: %s.'),
-                                                           $latest_version));
-                  Session::addMessageAfterRedirect(__('You will find it on the GLPI-PROJECT.org site.'));
-               } else {
-                  echo "<div class='center'>".sprintf(__('A new version is available: %s.'),
-                                                      $latest_version)."</div>";
-                  echo "<div class='center'>".__('You will find it on the GLPI-PROJECT.org site.').
-                       "</div>";
-               }
-
-            } else {
-               if ($messageafterredirect) {
-                  Session::addMessageAfterRedirect(sprintf(__('A new version is available: %s.'),
-                                                           $latest_version));
-               } else {
-                  return sprintf(__('A new version is available: %s.'), $latest_version);
-               }
-            }
-
+            return sprintf(__('A new version is available: %s.'), $latest_version);
          } else {
-            if (!$auto) {
-               if ($messageafterredirect) {
-                  Session::addMessageAfterRedirect(__('You have the latest available version'));
-               } else {
-                  echo "<div class='center'>".__('You have the latest available version')."</div>";
-               }
-
-            } else {
-               if ($messageafterredirect) {
-                  Session::addMessageAfterRedirect(__('You have the latest available version'));
-               } else {
-                  return __('You have the latest available version');
-               }
-            }
+            return __('You have the latest available version');
          }
       }
       return 1;

programming_language: PHP
filename: update.class.php
change_type: ModificationType.MODIFY
diff: @@ -458,6 +458,10 @@ class Update extends CommonGLPI {
          case "9.4.4":
             include_once "{$updir}update_943_945.php";
             update943to945();
+
+         case "9.4.5":
+            include_once "{$updir}update_945_946.php";
+            update945to946();
             break;
 
          case GLPI_VERSION:

programming_language: PHP
filename: update_084_085.php
change_type: ModificationType.MODIFY
diff: @@ -893,7 +893,7 @@ function update084to085() {
                          "`name` = 'check_update' AND `rights` = '1'") as $profrights) {
 
       $query  = "UPDATE `glpi_profilerights`
-                 SET `rights` = `rights` | " . Backup::CHECKUPDATE ."
+                 SET `rights` = `rights` | " . 1024 /*Backup::CHECKUPDATE*/ ."
                  WHERE `profiles_id` = '".$profrights['profiles_id']."'
                       AND `name` = 'backup'";
          $DB->queryOrDie($query, "0.85 update backup with check_update");

programming_language: PHP
filename: update_945_946.php
change_type: ModificationType.RENAME
diff: @@ -30,50 +30,29 @@
  * ---------------------------------------------------------------------
  */
 
-if (!defined('GLPI_ROOT')) {
-   die("Sorry. You can't access this file directly");
-}
-
 /**
- * Backup class
+ * Update from 9.4.5 to 9.4.6
  *
- * @since 0.85
+ * @return bool for success (will die for most error)
 **/
+function update945to946() {
+   global $DB, $migration;
 
+   $updateresult     = true;
 
-class Backup extends CommonGLPI {
-
-   static $rightname = 'backup';
-
-   const CHECKUPDATE = 1024;
-
-
-
-   /**
-    * @since 0.85.3
-    **/
-   static function canView() {
-      return Session::haveRight(self::$rightname, READ);
-   }
-
-
-   static function getTypeName($nb = 0) {
-      return __('Maintenance');
-   }
-
+   //TRANS: %s is the number of new version
+   $migration->displayTitle(sprintf(__('Update to %s'), '9.4.6'));
+   $migration->setVersion('9.4.6');
 
-   /**
-    * @since 0.85
-    *
-    * @see commonDBTM::getRights()
-   **/
-   function getRights($interface = 'central') {
+   $DB->deleteOrDie(
+      'glpi_profilerights',
+      [
+         'name'  => 'backup'
+      ]
+   );
 
-      $values = [READ                => __('Read'),
-                      CREATE              => __('Create'),
-                      PURGE               => _x('button', 'Delete permanently'),
-                      self::CHECKUPDATE   => __('Check for upgrade')];
-      return $values;
-   }
+   // ************ Keep it at the end **************
+   $migration->executeMigration();
 
+   return $updateresult;
 }

programming_language: PHP
filename: Html.php
change_type: ModificationType.MODIFY
diff: @@ -379,7 +379,6 @@ class Html extends \GLPITestCase {
          'Rule',
          'Profile',
          'QueuedNotification',
-         'Backup',
          'Glpi\\Event'
       ];
       $this->string($menu['admin']['title'])->isIdenticalTo('Administration');

programming_language: PHP