From 1838670e314e78891186fdec5077855544189bbc Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Wed, 7 Dec 2016 19:02:39 +0100
Subject: [PATCH] Fix several security holes on api when used by external users

---
 .../action/class/api_agendaevents.class.php   | 12 +++++--
 .../comm/propal/class/api_proposals.class.php |  4 ++-
 .../class/api_deprecated_commande.class.php   |  1 +
 htdocs/commande/class/api_orders.class.php    |  4 ++-
 .../class/api_deprecated_invoice.class.php    |  1 +
 .../facture/class/api_invoices.class.php      | 15 +++++----
 .../class/api_expensereports.class.php        |  7 +----
 .../class/api_supplier_invoices.class.php     |  4 ++-
 htdocs/projet/class/api_projects.class.php    |  4 ++-
 htdocs/projet/class/api_tasks.class.php       |  4 ++-
 htdocs/societe/class/api_contacts.class.php   | 31 +++++++++----------
 .../class/api_deprecated_thirdparty.class.php |  1 +
 .../societe/class/api_thirdparties.class.php  | 14 +++++----
 13 files changed, 60 insertions(+), 42 deletions(-)

diff --git a/htdocs/comm/action/class/api_agendaevents.class.php b/htdocs/comm/action/class/api_agendaevents.class.php
index 931283b0ab0..7d66dccdd63 100644
--- a/htdocs/comm/action/class/api_agendaevents.class.php
+++ b/htdocs/comm/action/class/api_agendaevents.class.php
@@ -102,13 +102,19 @@ class AgendaEvents extends DolibarrApi
         
         $obj_ret = array();
 
-        // case of external user, $societe param is ignored and replaced by user's socid
-        //$socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $societe;
-            
+        // case of external user
+        $socid = 0;
+        if (! empty(DolibarrApiAccess::$user->societe_id)) $socid = DolibarrApiAccess::$user->societe_id;
+        
+        // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
+        if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
+        
         $sql = "SELECT t.id as rowid";
         $sql.= " FROM ".MAIN_DB_PREFIX."actioncomm as t";
         $sql.= ' WHERE t.entity IN ('.getEntity('agenda', 1).')';
         if ($user_ids) $sql.=" AND t.fk_user_action IN (".$user_ids.")";
+        if ($socid > 0) $sql.= " AND t.fk_soc = ".$socid;
         // Insert sale filter
         if ($search_sale > 0)
         {
diff --git a/htdocs/comm/propal/class/api_proposals.class.php b/htdocs/comm/propal/class/api_proposals.class.php
index b4a15c2aa97..6ceac37a535 100644
--- a/htdocs/comm/propal/class/api_proposals.class.php
+++ b/htdocs/comm/propal/class/api_proposals.class.php
@@ -97,10 +97,12 @@ class Proposals extends DolibarrApi
         global $db, $conf;
         
         $obj_ret = array();
-        // case of external user, $thirdpartyid param is ignored and replaced by user's socid
+
+        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
         $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
             
         // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
         if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT t.rowid";
diff --git a/htdocs/commande/class/api_deprecated_commande.class.php b/htdocs/commande/class/api_deprecated_commande.class.php
index f5d799dd477..60c8c7f4aa8 100644
--- a/htdocs/commande/class/api_deprecated_commande.class.php
+++ b/htdocs/commande/class/api_deprecated_commande.class.php
@@ -115,6 +115,7 @@ class CommandeApi extends DolibarrApi
         $socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $societe;
 
         // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
         if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT s.rowid";
diff --git a/htdocs/commande/class/api_orders.class.php b/htdocs/commande/class/api_orders.class.php
index cc186367588..984ef5e6f43 100644
--- a/htdocs/commande/class/api_orders.class.php
+++ b/htdocs/commande/class/api_orders.class.php
@@ -101,10 +101,12 @@ class Orders extends DolibarrApi
         global $db, $conf;
 
         $obj_ret = array();
-        // case of external user, $thirdpartyid param is ignored and replaced by user's socid
+        
+        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
         $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
 
         // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
         if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT t.rowid";
diff --git a/htdocs/compta/facture/class/api_deprecated_invoice.class.php b/htdocs/compta/facture/class/api_deprecated_invoice.class.php
index b87bb2e9dc0..7dd8a7ee6bc 100644
--- a/htdocs/compta/facture/class/api_deprecated_invoice.class.php
+++ b/htdocs/compta/facture/class/api_deprecated_invoice.class.php
@@ -111,6 +111,7 @@ class InvoiceApi extends DolibarrApi
         $socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $socid;
             
         // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
         if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT s.rowid";
diff --git a/htdocs/compta/facture/class/api_invoices.class.php b/htdocs/compta/facture/class/api_invoices.class.php
index 888c05bff26..ddbae55f0ef 100644
--- a/htdocs/compta/facture/class/api_invoices.class.php
+++ b/htdocs/compta/facture/class/api_invoices.class.php
@@ -98,21 +98,24 @@ class Invoices extends DolibarrApi
         global $db, $conf;
         
         $obj_ret = array();
-        // case of external user, $thirdpartyid param is ignored and replaced by user's socid
+
+        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
         $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
-            
+        
         // If the internal user must only see his customers, force searching by him
-        if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
+        $search_sale = 0;
+        if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT t.rowid";
-        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
+        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
         $sql.= " FROM ".MAIN_DB_PREFIX."facture as t";
         
-        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
+        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
 
         $sql.= ' WHERE t.entity IN ('.getEntity('facture', 1).')';
-        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= " AND t.fk_soc = sc.fk_soc";
+        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= " AND t.fk_soc = sc.fk_soc";
         if ($socids) $sql.= " AND t.fk_soc IN (".$socids.")";
+
         if ($search_sale > 0) $sql.= " AND t.rowid = sc.fk_soc";		// Join for the needed table to filter by sale
         
 		// Filter by status
diff --git a/htdocs/expensereport/class/api_expensereports.class.php b/htdocs/expensereport/class/api_expensereports.class.php
index bf07089b71b..cb506d32cdf 100644
--- a/htdocs/expensereport/class/api_expensereports.class.php
+++ b/htdocs/expensereport/class/api_expensereports.class.php
@@ -101,17 +101,12 @@ class ExpenseReports extends DolibarrApi
 
         // case of external user, $societe param is ignored and replaced by user's socid
         //$socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $societe;
-            
+        
         $sql = "SELECT t.rowid";
         $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as t";
         $sql.= ' WHERE t.entity IN ('.getEntity('expensereport', 1).')';
         if ($user_ids) $sql.=" AND t.fk_user_author IN (".$user_ids.")";
         
-        // Insert sale filter
-        if ($search_sale > 0)
-        {
-            $sql .= " AND sc.fk_user = ".$search_sale;
-        }
         // Add sql filters
         if ($sqlfilters) 
         {
diff --git a/htdocs/fourn/class/api_supplier_invoices.class.php b/htdocs/fourn/class/api_supplier_invoices.class.php
index 660e64147ed..2348abfdc48 100644
--- a/htdocs/fourn/class/api_supplier_invoices.class.php
+++ b/htdocs/fourn/class/api_supplier_invoices.class.php
@@ -99,10 +99,12 @@ class SupplierInvoices extends DolibarrApi
         global $db, $conf;
         
         $obj_ret = array();
-        // case of external user, $thirdpartyid param is ignored and replaced by user's socid
+
+        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
         $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
             
         // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
         if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT t.rowid";
diff --git a/htdocs/projet/class/api_projects.class.php b/htdocs/projet/class/api_projects.class.php
index 2b5ee92d878..78e7954a097 100644
--- a/htdocs/projet/class/api_projects.class.php
+++ b/htdocs/projet/class/api_projects.class.php
@@ -102,10 +102,12 @@ class Projects extends DolibarrApi
         global $db, $conf;
 
         $obj_ret = array();
-        // case of external user, $thirdpartyid param is ignored and replaced by user's socid
+        
+        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
         $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
 
         // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
         if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT t.rowid";
diff --git a/htdocs/projet/class/api_tasks.class.php b/htdocs/projet/class/api_tasks.class.php
index c88850ca403..1678e43328f 100644
--- a/htdocs/projet/class/api_tasks.class.php
+++ b/htdocs/projet/class/api_tasks.class.php
@@ -109,10 +109,12 @@ class Tasks extends DolibarrApi
         global $db, $conf;
 
         $obj_ret = array();
-        // case of external user, $thirdpartyid param is ignored and replaced by user's socid
+        
+        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
         $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
 
         // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
         if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT t.rowid";
diff --git a/htdocs/societe/class/api_contacts.class.php b/htdocs/societe/class/api_contacts.class.php
index 9f09f7f7408..da8e930a0ce 100644
--- a/htdocs/societe/class/api_contacts.class.php
+++ b/htdocs/societe/class/api_contacts.class.php
@@ -84,41 +84,40 @@ class Contacts extends DolibarrApi
 	 * 
 	 * Get a list of contacts
 	 * 
-	 * @param string	$sortfield	Sort field
-	 * @param string	$sortorder	Sort order
-	 * @param int		$limit		Limit for list
-	 * @param int		$page		Page number
-	 * @param int		$socid		ID of thirdparty to filter list
-     * @param string    $sqlfilters Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
-	 * @return array                Array of contact objects
+	 * @param string	$sortfield	        Sort field
+	 * @param string	$sortorder	        Sort order
+	 * @param int		$limit		        Limit for list
+	 * @param int		$page		        Page number
+     * @param string   	$thirdparty_ids	    Thirdparty ids to filter projects of. {@example '1' or '1,2,3'} {@pattern /^[0-9,]*$/i}
+     * @param string    $sqlfilters         Other criteria to filter answers separated by a comma. Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')"
+	 * @return array                        Array of contact objects
      * 
 	 * @throws RestException
 	 */
-	function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $page = 0, $socid = 0, $sqlfilters = '') {
+	function index($sortfield = "t.rowid", $sortorder = 'ASC', $limit = 0, $page = 0, $thirdparty_ids = '', $sqlfilters = '') {
 		global $db, $conf;
 
 		$obj_ret = array();
 
-		if (!$socid)
-		{
-			$socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : '';
-		}
+        // case of external user, $thirdparty_ids param is ignored and replaced by user's socid
+		$socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : $thirdparty_ids;
 
 		// If the internal user must only see his customers, force searching by him
-		if (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid)
+		$search_sale = 0;
+		if (!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids)
 			$search_sale = DolibarrApiAccess::$user->id;
 
 		$sql = "SELECT t.rowid";
 		$sql.= " FROM " . MAIN_DB_PREFIX . "socpeople as t";
-		if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) {
+		if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) {
 			// We need this table joined to the select in order to filter by sale
 			$sql.= ", " . MAIN_DB_PREFIX . "societe_commerciaux as sc"; 
 		}
 		$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "societe as s ON t.fk_soc = s.rowid";
 		$sql.= ' WHERE t.entity IN (' . getEntity('socpeople', 1) . ')';
-		if ($socid) $sql.= " AND t.fk_soc = " . $socid;
+		if ($socids) $sql.= " AND t.fk_soc IN (" . $socids . ")";
 
-		if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0)
+		if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0)
 			$sql.= " AND t.fk_soc = sc.fk_soc";
 		if ($search_sale > 0)
 			$sql.= " AND s.rowid = sc.fk_soc";  // Join for the needed table to filter by sale
diff --git a/htdocs/societe/class/api_deprecated_thirdparty.class.php b/htdocs/societe/class/api_deprecated_thirdparty.class.php
index 6086f2366d8..8b0302f9c11 100644
--- a/htdocs/societe/class/api_deprecated_thirdparty.class.php
+++ b/htdocs/societe/class/api_deprecated_thirdparty.class.php
@@ -165,6 +165,7 @@ class ThirdpartyApi extends DolibarrApi
         $socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : '';
             
         // If the internal user must only see his customers, force searching by him
+        $search_sale = 0;
         if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT s.rowid";
diff --git a/htdocs/societe/class/api_thirdparties.class.php b/htdocs/societe/class/api_thirdparties.class.php
index bc156b5cc4a..674d8abcf42 100644
--- a/htdocs/societe/class/api_thirdparties.class.php
+++ b/htdocs/societe/class/api_thirdparties.class.php
@@ -102,25 +102,27 @@ class Thirdparties extends DolibarrApi
         
         $obj_ret = array();
         
-        $socid = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : '';
+        // case of external user, we force socids
+        $socids = DolibarrApiAccess::$user->societe_id ? DolibarrApiAccess::$user->societe_id : '';
             
         // If the internal user must only see his customers, force searching by him
-        if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) $search_sale = DolibarrApiAccess::$user->id;
+        $search_sale = 0;
+        if (! DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) $search_sale = DolibarrApiAccess::$user->id;
 
         $sql = "SELECT t.rowid";
-        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
+        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql .= ", sc.fk_soc, sc.fk_user"; // We need these fields in order to filter by sale (including the case where the user can only see his prospects)
         $sql.= " FROM ".MAIN_DB_PREFIX."societe as t";
         
-        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
+        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; // We need this table joined to the select in order to filter by sale
         $sql.= ", ".MAIN_DB_PREFIX."c_stcomm as st";
         $sql.= " WHERE t.fk_stcomm = st.id";
         if ($mode == 1) $sql.= " AND t.client IN (1, 3)";
         if ($mode == 2) $sql.= " AND t.client IN (2, 3)";
         if ($mode == 3) $sql.= " AND t.client IN (0)";
         $sql.= ' AND t.entity IN ('.getEntity('societe', 1).')';
-        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socid) || $search_sale > 0) $sql.= " AND t.rowid = sc.fk_soc";
+        if ((!DolibarrApiAccess::$user->rights->societe->client->voir && !$socids) || $search_sale > 0) $sql.= " AND t.rowid = sc.fk_soc";
         //if ($email != NULL) $sql.= " AND s.email = \"".$email."\"";
-        if ($socid) $sql.= " AND t.rowid = ".$socid;
+        if ($socid) $sql.= " AND t.rowid IN (".$socids.")";
         if ($search_sale > 0) $sql.= " AND t.rowid = sc.fk_soc";		// Join for the needed table to filter by sale
         // Insert sale filter
         if ($search_sale > 0)
-- 
GitLab