From c5850d29e7b2e5c98f3c0dd0622219de08b78a42 Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Mon, 26 Dec 2016 19:51:24 +0100
Subject: [PATCH] Fix checksum integrity. Also add a global checksum.

---
 build/generate_filelist_xml.php   | 22 +++++++++++--
 htdocs/admin/system/filecheck.php | 55 +++++++++++++++++++++++--------
 htdocs/langs/en_US/admin.lang     |  1 +
 3 files changed, 63 insertions(+), 15 deletions(-)

diff --git a/build/generate_filelist_xml.php b/build/generate_filelist_xml.php
index 1bc0e2b6620..07e87dd86bb 100755
--- a/build/generate_filelist_xml.php
+++ b/build/generate_filelist_xml.php
@@ -65,6 +65,8 @@ fputs($fp, '<checksum_list version="'.$release.'">'."\n");
 
 fputs($fp, '<dolibarr_htdocs_dir>'."\n");
 
+$checksumconcat=array();
+
 $dir_iterator1 = new RecursiveDirectoryIterator(dirname(__FILE__).'/../htdocs/');
 $iterator1 = new RecursiveIteratorIterator($dir_iterator1);
 // need to ignore document custom etc
@@ -81,12 +83,22 @@ foreach ($files as $file) {
         $needtoclose=1;
     }
     if (filetype($file)=="file") {
-        fputs($fp, '<md5file name="'.basename($file).'">'.md5_file($file).'</md5file>'."\n");
+        $md5=md5_file($file);
+        $checksumconcat[]=$md5;
+        fputs($fp, '<md5file name="'.basename($file).'">'.$md5.'</md5file>'."\n");
     }
 }
 fputs($fp, '</dir>'."\n");
 fputs($fp, '</dolibarr_htdocs_dir>'."\n");
 
+asort($checksumconcat); // Sort list of checksum
+//var_dump($checksumconcat);
+fputs($fp, '<dolibarr_htdocs_dir_checksum>'."\n");
+fputs($fp, md5(join(',',$checksumconcat))."\n");
+fputs($fp, '</dolibarr_htdocs_dir_checksum>'."\n");
+
+
+$checksumconcat=array();
 
 fputs($fp, '<dolibarr_script_dir version="'.$release.'">'."\n");
 
@@ -106,12 +118,18 @@ foreach ($files as $file) {
         $needtoclose=1;
     }
     if (filetype($file)=="file") {
-        fputs($fp, '<md5file name="'.basename($file).'">'.md5_file($file).'</md5file>'."\n");
+        $md5=md5_file($file);
+        $checksumconcat[]=$md5;
+        fputs($fp, '<md5file name="'.basename($file).'">'.$md5.'</md5file>'."\n");
     }
 }
 fputs($fp, '</dir>'."\n");
 fputs($fp, '</dolibarr_script_dir>'."\n");
 
+asort($checksumconcat); // Sort list of checksum
+fputs($fp, '<dolibarr_script_dir_checksum>'."\n");
+fputs($fp, md5(join(',',$checksumconcat))."\n");
+fputs($fp, '</dolibarr_script_dir_checksum>'."\n");
 
 fputs($fp, '</checksum_list>'."\n");
 fclose($fp);
diff --git a/htdocs/admin/system/filecheck.php b/htdocs/admin/system/filecheck.php
index 0d6c2e5cd1d..1340b5ae3c1 100644
--- a/htdocs/admin/system/filecheck.php
+++ b/htdocs/admin/system/filecheck.php
@@ -148,11 +148,14 @@ if (GETPOST('target') == 'remote')
 
 if ($xml)
 {
+    $checksumconcat = array();
+
+    // Scan htdocs
     if (is_object($xml->dolibarr_htdocs_dir[0]))
     {
-    	$file_list = array();
-        $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0]);		// Fill array $file_list
-
+        $file_list = array();
+        $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', DOL_DOCUMENT_ROOT, $checksumconcat);		// Fill array $file_list
+    
         print '<table class="noborder">';
         print '<tr class="liste_titre">';
         print '<td>' . $langs->trans("FilesMissing") . '</td>';
@@ -223,6 +226,29 @@ if ($xml)
         print 'Error: Failed to found dolibarr_htdocs_dir into XML file '.$xmlfile;
         $error++;
     }
+
+
+    // Scan scripts
+    /*
+    if (is_object($xml->dolibarr_script_dir[0]))
+    {
+        $file_list = array();
+        $ret = getFilesUpdated($file_list, $xml->dolibarr_htdocs_dir[0], '', ???, $checksumconcat);		// Fill array $file_list
+    }*/
+    
+    
+    asort($checksumconcat); // Sort list of checksum        
+    //var_dump($checksumconcat);
+    $checksumget = md5(join(',',$checksumconcat));
+    $checksumtoget = $xml->dolibarr_htdocs_dir_checksum;
+    if ($checksumtoget)
+    {
+        print '<br>';
+        print '<strong>'.$langs->trans("GlobalChecksum").'</strong><br>';
+        print $langs->trans("ExpectedChecksum").' = '.$checksumtoget.'<br>';
+        print $langs->trans("CurrentChecksum").' = '.$checksumget;
+    }
+    
 }
 
 
@@ -239,12 +265,14 @@ exit($error);
  * Function to get list of updated or modified files.
  * $file_list is used as global variable
  *
- * @param	array				$file_list	Array for response
- * @param   SimpleXMLElement	$dir    	SimpleXMLElement of files to test
- * @param   string   			$path   	Path of file
- * @return  array               			Array of filenames
+ * @param	array				$file_list	        Array for response
+ * @param   SimpleXMLElement	$dir    	        SimpleXMLElement of files to test
+ * @param   string   			$path   	        Path of files relative to $pathref. We start with ''. Used by recursive calls.
+ * @param   string              $pathref            Path ref (DOL_DOCUMENT_ROOT)
+ * @param   array               $checksumconcat     Array of checksum
+ * @return  array               			        Array of filenames
  */
-function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '')
+function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathref = '', &$checksumconcat = array())
 {
     $exclude = 'install';
 
@@ -252,20 +280,21 @@ function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '')
     {
         $filename = $path.$file['name'];
 
-        if (preg_match('#'.$exclude.'#', $filename)) continue;
+        //if (preg_match('#'.$exclude.'#', $filename)) continue;
 
-        if (!file_exists(DOL_DOCUMENT_ROOT.'/'.$filename))
+        if (!file_exists($pathref.'/'.$filename))
         {
             $file_list['missing'][] = array('filename'=>$filename, 'expectedmd5'=>(string) $file);
         }
         else
 		{
-            $md5_local = md5_file(DOL_DOCUMENT_ROOT.'/'.$filename);
+            $md5_local = md5_file($pathref.'/'.$filename);
             if ($md5_local != (string) $file) $file_list['updated'][] = array('filename'=>$filename, 'expectedmd5'=>(string) $file, 'md5'=>(string) $md5_local);
-        }
+            $checksumconcat[] = $md5_local;
+		}
     }
 
-    foreach ($dir->dir as $subdir) getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/');
+    foreach ($dir->dir as $subdir) getFilesUpdated($file_list, $subdir, $path.$subdir['name'].'/', $pathref, $checksumconcat);
 
     return $file_list;
 }
diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang
index d8b0c586584..4f029afd8d8 100644
--- a/htdocs/langs/en_US/admin.lang
+++ b/htdocs/langs/en_US/admin.lang
@@ -12,6 +12,7 @@ FileCheck=Files integrity checker
 FileCheckDesc=This tool allows you to check the integrity of files of your application, comparing each files with the official ones. You can use this tool to detect if some files were modified by a hacker for example.
 FileIntegrityIsStrictlyConformedWithReference=Files integrity is strictly conformed with the reference.
 FileIntegritySomeFilesWereRemovedOrModified=Files integrity check has failed. Some files were modified of removed.
+GlobalChecksum=Global checksum
 MakeIntegrityAnalysisFrom=Make integrity analysis of application files from
 LocalSignature=Embedded local signature (less reliable)
 RemoteSignature=Remote distant signature (more reliable)
-- 
GitLab