dolibarr  16.0.5
security.lib.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2008-2021 Laurent Destailleur <eldy@users.sourceforge.net>
3  * Copyright (C) 2008-2021 Regis Houssin <regis.houssin@inodbox.com>
4  * Copyright (C) 2020 Ferran Marcet <fmarcet@2byte.es>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <https://www.gnu.org/licenses/>.
18  * or see https://www.gnu.org/
19  */
20 
38 function dol_encode($chain, $key = '1')
39 {
40  if (is_numeric($key) && $key == '1') { // rule 1 is offset of 17 for char
41  $output_tab = array();
42  $strlength = dol_strlen($chain);
43  for ($i = 0; $i < $strlength; $i++) {
44  $output_tab[$i] = chr(ord(substr($chain, $i, 1)) + 17);
45  }
46  $chain = implode("", $output_tab);
47  } elseif ($key) {
48  $result = '';
49  $strlength = dol_strlen($chain);
50  for ($i = 0; $i < $strlength; $i++) {
51  $keychar = substr($key, ($i % strlen($key)) - 1, 1);
52  $result .= chr(ord(substr($chain, $i, 1)) + (ord($keychar) - 65));
53  }
54  $chain = $result;
55  }
56 
57  return base64_encode($chain);
58 }
59 
69 function dol_decode($chain, $key = '1')
70 {
71  $chain = base64_decode($chain);
72 
73  if (is_numeric($key) && $key == '1') { // rule 1 is offset of 17 for char
74  $output_tab = array();
75  $strlength = dol_strlen($chain);
76  for ($i = 0; $i < $strlength; $i++) {
77  $output_tab[$i] = chr(ord(substr($chain, $i, 1)) - 17);
78  }
79 
80  $chain = implode("", $output_tab);
81  } elseif ($key) {
82  $result = '';
83  $strlength = dol_strlen($chain);
84  for ($i = 0; $i < $strlength; $i++) {
85  $keychar = substr($key, ($i % strlen($key)) - 1, 1);
86  $result .= chr(ord(substr($chain, $i, 1)) - (ord($keychar) - 65));
87  }
88  $chain = $result;
89  }
90 
91  return $chain;
92 }
93 
104 function dol_hash($chain, $type = '0')
105 {
106  global $conf;
107 
108  // No need to add salt for password_hash
109  if (($type == '0' || $type == 'auto') && !empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists('password_hash')) {
110  return password_hash($chain, PASSWORD_DEFAULT);
111  }
112 
113  // Salt value
114  if (!empty($conf->global->MAIN_SECURITY_SALT) && $type != '4' && $type !== 'openldap') {
115  $chain = $conf->global->MAIN_SECURITY_SALT.$chain;
116  }
117 
118  if ($type == '1' || $type == 'sha1') {
119  return sha1($chain);
120  } elseif ($type == '2' || $type == 'sha1md5') {
121  return sha1(md5($chain));
122  } elseif ($type == '3' || $type == 'md5') {
123  return md5($chain);
124  } elseif ($type == '4' || $type == 'openldap') {
125  return dolGetLdapPasswordHash($chain, getDolGlobalString('LDAP_PASSWORD_HASH_TYPE', 'md5'));
126  } elseif ($type == '5' || $type == 'sha256') {
127  return hash('sha256', $chain);
128  } elseif ($type == '6' || $type == 'password_hash') {
129  return password_hash($chain, PASSWORD_DEFAULT);
130  } elseif (!empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'sha1') {
131  return sha1($chain);
132  } elseif (!empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'sha1md5') {
133  return sha1(md5($chain));
134  }
135 
136  // No particular encoding defined, use default
137  return md5($chain);
138 }
139 
151 function dol_verifyHash($chain, $hash, $type = '0')
152 {
153  global $conf;
154 
155  if ($type == '0' && !empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists('password_verify')) {
156  if ($hash[0] == '$') {
157  return password_verify($chain, $hash);
158  } elseif (strlen($hash) == 32) {
159  return dol_verifyHash($chain, $hash, '3'); // md5
160  } elseif (strlen($hash) == 40) {
161  return dol_verifyHash($chain, $hash, '2'); // sha1md5
162  }
163 
164  return false;
165  }
166 
167  return dol_hash($chain, $type) == $hash;
168 }
169 
177 function dolGetLdapPasswordHash($password, $type = 'md5')
178 {
179  if (empty($type)) {
180  $type = 'md5';
181  }
182 
183  $salt = substr(sha1(time()), 0, 8);
184 
185  if ($type === 'md5') {
186  return '{MD5}' . base64_encode(hash("md5", $password, true)); //For OpenLdap with md5 (based on an unencrypted password in base)
187  } elseif ($type === 'md5frommd5') {
188  return '{MD5}' . base64_encode(hex2bin($password)); // Create OpenLDAP MD5 password from Dolibarr MD5 password
189  } elseif ($type === 'smd5') {
190  return "{SMD5}" . base64_encode(hash("md5", $password . $salt, true) . $salt);
191  } elseif ($type === 'sha') {
192  return '{SHA}' . base64_encode(hash("sha1", $password, true));
193  } elseif ($type === 'ssha') {
194  return "{SSHA}" . base64_encode(hash("sha1", $password . $salt, true) . $salt);
195  } elseif ($type === 'sha256') {
196  return "{SHA256}" . base64_encode(hash("sha256", $password, true));
197  } elseif ($type === 'ssha256') {
198  return "{SSHA256}" . base64_encode(hash("sha256", $password . $salt, true) . $salt);
199  } elseif ($type === 'sha384') {
200  return "{SHA384}" . base64_encode(hash("sha384", $password, true));
201  } elseif ($type === 'ssha384') {
202  return "{SSHA384}" . base64_encode(hash("sha384", $password . $salt, true) . $salt);
203  } elseif ($type === 'sha512') {
204  return "{SHA512}" . base64_encode(hash("sha512", $password, true));
205  } elseif ($type === 'ssha512') {
206  return "{SSHA512}" . base64_encode(hash("sha512", $password . $salt, true) . $salt);
207  } elseif ($type === 'crypt') {
208  return '{CRYPT}' . crypt($password, $salt);
209  } elseif ($type === 'clear') {
210  return '{CLEAR}' . $password; // Just for test, plain text password is not secured !
211  }
212 }
213 
234 function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $feature2 = '', $dbt_keyfield = 'fk_soc', $dbt_select = 'rowid', $isdraft = 0, $mode = 0)
235 {
236  global $db, $conf;
237  global $hookmanager;
238 
239  $objectid = ((int) $objectid); // For the case value is coming from a non sanitized user input
240 
241  //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename, $feature2, $dbt_socfield, $dbt_select, $isdraft");
242  //print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid;
243  //print ", dbtablename=".$tableandshare.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select;
244  //print ", perm: ".$features."->".$feature2."=".($user->rights->$features->$feature2->lire)."<br>";
245 
246  $parentfortableentity = '';
247 
248  // Fix syntax of $features param
249  $originalfeatures = $features;
250  if ($features == 'facturerec') {
251  $features = 'facture';
252  }
253  if ($features == 'mo') {
254  $features = 'mrp';
255  }
256  if ($features == 'member') {
257  $features = 'adherent';
258  }
259  if ($features == 'subscription') {
260  $features = 'adherent';
261  $feature2 = 'cotisation';
262  };
263  if ($features == 'websitepage') {
264  $features = 'website';
265  $tableandshare = 'website_page';
266  $parentfortableentity = 'fk_website@website';
267  }
268  if ($features == 'project') {
269  $features = 'projet';
270  }
271  if ($features == 'product') {
272  $features = 'produit';
273  }
274 
275  // Get more permissions checks from hooks
276  $parameters = array('features'=>$features, 'originalfeatures'=>$originalfeatures, 'objectid'=>$objectid, 'dbt_select'=>$dbt_select, 'idtype'=>$dbt_select, 'isdraft'=>$isdraft);
277  $reshook = $hookmanager->executeHooks('restrictedArea', $parameters);
278 
279  if (isset($hookmanager->resArray['result'])) {
280  if ($hookmanager->resArray['result'] == 0) {
281  if ($mode) {
282  return 0;
283  } else {
284  accessforbidden(); // Module returns 0, so access forbidden
285  }
286  }
287  }
288  if ($reshook > 0) { // No other test done.
289  return 1;
290  }
291 
292  // To avoid access forbidden with numeric ref
293  if ($dbt_select != 'rowid' && $dbt_select != 'id') {
294  $objectid = "'".$objectid."'";
295  }
296 
297  // Features/modules to check
298  $featuresarray = array($features);
299  if (preg_match('/&/', $features)) {
300  $featuresarray = explode("&", $features);
301  } elseif (preg_match('/\|/', $features)) {
302  $featuresarray = explode("|", $features);
303  }
304 
305  // More subfeatures to check
306  if (!empty($feature2)) {
307  $feature2 = explode("|", $feature2);
308  }
309 
310  $listofmodules = explode(',', $conf->global->MAIN_MODULES_FOR_EXTERNAL);
311 
312  // Check read permission from module
313  $readok = 1;
314  $nbko = 0;
315  foreach ($featuresarray as $feature) { // first we check nb of test ko
316  $featureforlistofmodule = $feature;
317  if ($featureforlistofmodule == 'produit') {
318  $featureforlistofmodule = 'product';
319  }
320  if (!empty($user->socid) && !empty($conf->global->MAIN_MODULES_FOR_EXTERNAL) && !in_array($featureforlistofmodule, $listofmodules)) { // If limits on modules for external users, module must be into list of modules for external users
321  $readok = 0;
322  $nbko++;
323  continue;
324  }
325 
326  if ($feature == 'societe') {
327  if (empty($user->rights->societe->lire) && empty($user->rights->fournisseur->lire)) {
328  $readok = 0;
329  $nbko++;
330  }
331  } elseif ($feature == 'contact') {
332  if (empty($user->rights->societe->contact->lire)) {
333  $readok = 0;
334  $nbko++;
335  }
336  } elseif ($feature == 'produit|service') {
337  if (!$user->rights->produit->lire && !$user->rights->service->lire) {
338  $readok = 0;
339  $nbko++;
340  }
341  } elseif ($feature == 'prelevement') {
342  if (!$user->rights->prelevement->bons->lire) {
343  $readok = 0;
344  $nbko++;
345  }
346  } elseif ($feature == 'cheque') {
347  if (empty($user->rights->banque->cheque)) {
348  $readok = 0;
349  $nbko++;
350  }
351  } elseif ($feature == 'projet') {
352  if (!$user->rights->projet->lire && empty($user->rights->projet->all->lire)) {
353  $readok = 0;
354  $nbko++;
355  }
356  } elseif ($feature == 'payment') {
357  if (!$user->rights->facture->lire) {
358  $readok = 0;
359  $nbko++;
360  }
361  } elseif ($feature == 'payment_supplier') {
362  if (empty($user->rights->fournisseur->facture->lire)) {
363  $readok = 0;
364  $nbko++;
365  }
366  } elseif (!empty($feature2)) { // This is for permissions on 2 levels
367  $tmpreadok = 1;
368  foreach ($feature2 as $subfeature) {
369  if ($subfeature == 'user' && $user->id == $objectid) {
370  continue; // A user can always read its own card
371  }
372  if (!empty($subfeature) && empty($user->rights->$feature->$subfeature->lire) && empty($user->rights->$feature->$subfeature->read)) {
373  $tmpreadok = 0;
374  } elseif (empty($subfeature) && empty($user->rights->$feature->lire) && empty($user->rights->$feature->read)) {
375  $tmpreadok = 0;
376  } else {
377  $tmpreadok = 1;
378  break;
379  } // Break is to bypass second test if the first is ok
380  }
381  if (!$tmpreadok) { // We found a test on feature that is ko
382  $readok = 0; // All tests are ko (we manage here the and, the or will be managed later using $nbko).
383  $nbko++;
384  }
385  } elseif (!empty($feature) && ($feature != 'user' && $feature != 'usergroup')) { // This is permissions on 1 level
386  if (empty($user->rights->$feature->lire)
387  && empty($user->rights->$feature->read)
388  && empty($user->rights->$feature->run)) {
389  $readok = 0;
390  $nbko++;
391  }
392  }
393  }
394 
395  // If a or and at least one ok
396  if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) {
397  $readok = 1;
398  }
399 
400  if (!$readok) {
401  if ($mode) {
402  return 0;
403  } else {
404  accessforbidden();
405  }
406  }
407  //print "Read access is ok";
408 
409  // Check write permission from module (we need to know write permission to create but also to delete drafts record or to upload files)
410  $createok = 1;
411  $nbko = 0;
412  $wemustcheckpermissionforcreate = (GETPOST('sendit', 'alpha') || GETPOST('linkit', 'alpha') || in_array(GETPOST('action', 'aZ09'), array('create', 'update', 'add_element_resource', 'confirm_delete_linked_resource')) || GETPOST('roworder', 'alpha', 2));
413  $wemustcheckpermissionfordeletedraft = ((GETPOST("action", "aZ09") == 'confirm_delete' && GETPOST("confirm", "aZ09") == 'yes') || GETPOST("action", "aZ09") == 'delete');
414 
415  if ($wemustcheckpermissionforcreate || $wemustcheckpermissionfordeletedraft) {
416  foreach ($featuresarray as $feature) {
417  if ($feature == 'contact') {
418  if (empty($user->rights->societe->contact->creer)) {
419  $createok = 0;
420  $nbko++;
421  }
422  } elseif ($feature == 'produit|service') {
423  if (empty($user->rights->produit->creer) && empty($user->rights->service->creer)) {
424  $createok = 0;
425  $nbko++;
426  }
427  } elseif ($feature == 'prelevement') {
428  if (!$user->rights->prelevement->bons->creer) {
429  $createok = 0;
430  $nbko++;
431  }
432  } elseif ($feature == 'commande_fournisseur') {
433  if (empty($user->rights->fournisseur->commande->creer) || empty($user->rights->supplier_order->creer)) {
434  $createok = 0;
435  $nbko++;
436  }
437  } elseif ($feature == 'banque') {
438  if (empty($user->rights->banque->modifier)) {
439  $createok = 0;
440  $nbko++;
441  }
442  } elseif ($feature == 'cheque') {
443  if (empty($user->rights->banque->cheque)) {
444  $createok = 0;
445  $nbko++;
446  }
447  } elseif ($feature == 'import') {
448  if (empty($user->rights->import->run)) {
449  $createok = 0;
450  $nbko++;
451  }
452  } elseif ($feature == 'ecm') {
453  if (!$user->rights->ecm->upload) {
454  $createok = 0;
455  $nbko++;
456  }
457  } elseif (!empty($feature2)) { // This is for permissions on one level
458  foreach ($feature2 as $subfeature) {
459  if ($subfeature == 'user' && $user->id == $objectid && $user->rights->user->self->creer) {
460  continue; // User can edit its own card
461  }
462  if ($subfeature == 'user' && $user->id == $objectid && $user->rights->user->self->password) {
463  continue; // User can edit its own password
464  }
465  if ($subfeature == 'user' && $user->id != $objectid && $user->rights->user->user->password) {
466  continue; // User can edit another user's password
467  }
468 
469  if (empty($user->rights->$feature->$subfeature->creer)
470  && empty($user->rights->$feature->$subfeature->write)
471  && empty($user->rights->$feature->$subfeature->create)) {
472  $createok = 0;
473  $nbko++;
474  } else {
475  $createok = 1;
476  // Break to bypass second test if the first is ok
477  break;
478  }
479  }
480  } elseif (!empty($feature)) { // This is for permissions on 2 levels ('creer' or 'write')
481  //print '<br>feature='.$feature.' creer='.$user->rights->$feature->creer.' write='.$user->rights->$feature->write; exit;
482  if (empty($user->rights->$feature->creer)
483  && empty($user->rights->$feature->write)
484  && empty($user->rights->$feature->create)) {
485  $createok = 0;
486  $nbko++;
487  }
488  }
489  }
490 
491  // If a or and at least one ok
492  if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) {
493  $createok = 1;
494  }
495 
496  if ($wemustcheckpermissionforcreate && !$createok) {
497  if ($mode) {
498  return 0;
499  } else {
500  accessforbidden();
501  }
502  }
503  //print "Write access is ok";
504  }
505 
506  // Check create user permission
507  $createuserok = 1;
508  if (GETPOST('action', 'aZ09') == 'confirm_create_user' && GETPOST("confirm", 'aZ09') == 'yes') {
509  if (!$user->rights->user->user->creer) {
510  $createuserok = 0;
511  }
512 
513  if (!$createuserok) {
514  if ($mode) {
515  return 0;
516  } else {
517  accessforbidden();
518  }
519  }
520  //print "Create user access is ok";
521  }
522 
523  // Check delete permission from module
524  $deleteok = 1;
525  $nbko = 0;
526  if ((GETPOST("action", "aZ09") == 'confirm_delete' && GETPOST("confirm", "aZ09") == 'yes') || GETPOST("action", "aZ09") == 'delete') {
527  foreach ($featuresarray as $feature) {
528  if ($feature == 'contact') {
529  if (!$user->rights->societe->contact->supprimer) {
530  $deleteok = 0;
531  }
532  } elseif ($feature == 'produit|service') {
533  if (!$user->rights->produit->supprimer && !$user->rights->service->supprimer) {
534  $deleteok = 0;
535  }
536  } elseif ($feature == 'commande_fournisseur') {
537  if (!$user->rights->fournisseur->commande->supprimer) {
538  $deleteok = 0;
539  }
540  } elseif ($feature == 'payment_supplier') { // Permission to delete a payment of an invoice is permission to edit an invoice.
541  if (!$user->rights->fournisseur->facture->creer) {
542  $deleteok = 0;
543  }
544  } elseif ($feature == 'payment') {
545  if (!$user->rights->facture->paiement) {
546  $deleteok = 0;
547  }
548  } elseif ($feature == 'banque') {
549  if (empty($user->rights->banque->modifier)) {
550  $deleteok = 0;
551  }
552  } elseif ($feature == 'cheque') {
553  if (empty($user->rights->banque->cheque)) {
554  $deleteok = 0;
555  }
556  } elseif ($feature == 'ecm') {
557  if (!$user->rights->ecm->upload) {
558  $deleteok = 0;
559  }
560  } elseif ($feature == 'ftp') {
561  if (!$user->rights->ftp->write) {
562  $deleteok = 0;
563  }
564  } elseif ($feature == 'salaries') {
565  if (!$user->rights->salaries->delete) {
566  $deleteok = 0;
567  }
568  } elseif ($feature == 'adherent') {
569  if (empty($user->rights->adherent->supprimer)) {
570  $deleteok = 0;
571  }
572  } elseif ($feature == 'paymentbybanktransfer') {
573  if (empty($user->rights->paymentbybanktransfer->create)) { // There is no delete permission
574  $deleteok = 0;
575  }
576  } elseif ($feature == 'prelevement') {
577  if (empty($user->rights->prelevement->bons->creer)) { // There is no delete permission
578  $deleteok = 0;
579  }
580  } elseif (!empty($feature2)) { // This is for permissions on 2 levels
581  foreach ($feature2 as $subfeature) {
582  if (empty($user->rights->$feature->$subfeature->supprimer) && empty($user->rights->$feature->$subfeature->delete)) {
583  $deleteok = 0;
584  } else {
585  $deleteok = 1;
586  break;
587  } // For bypass the second test if the first is ok
588  }
589  } elseif (!empty($feature)) { // This is used for permissions on 1 level
590  //print '<br>feature='.$feature.' creer='.$user->rights->$feature->supprimer.' write='.$user->rights->$feature->delete;
591  if (empty($user->rights->$feature->supprimer)
592  && empty($user->rights->$feature->delete)
593  && empty($user->rights->$feature->run)) {
594  $deleteok = 0;
595  }
596  }
597  }
598 
599  // If a or and at least one ok
600  if (preg_match('/\|/', $features) && $nbko < count($featuresarray)) {
601  $deleteok = 1;
602  }
603 
604  if (!$deleteok && !($isdraft && $createok)) {
605  if ($mode) {
606  return 0;
607  } else {
608  accessforbidden();
609  }
610  }
611  //print "Delete access is ok";
612  }
613 
614  // If we have a particular object to check permissions on, we check if $user has permission
615  // for this given object (link to company, is contact for project, ...)
616  if (!empty($objectid) && $objectid > 0) {
617  $ok = checkUserAccessToObject($user, $featuresarray, $objectid, $tableandshare, $feature2, $dbt_keyfield, $dbt_select, $parentfortableentity);
618  $params = array('objectid' => $objectid, 'features' => join(',', $featuresarray), 'features2' => $feature2);
619  //print 'checkUserAccessToObject ok='.$ok;
620  if ($mode) {
621  return $ok ? 1 : 0;
622  } else {
623  return $ok ? 1 : accessforbidden('', 1, 1, 0, $params);
624  }
625  }
626 
627  return 1;
628 }
629 
645 function checkUserAccessToObject($user, array $featuresarray, $object = 0, $tableandshare = '', $feature2 = '', $dbt_keyfield = '', $dbt_select = 'rowid', $parenttableforentity = '')
646 {
647  global $db, $conf;
648 
649  if (is_object($object)) {
650  $objectid = $object->id;
651  } else {
652  $objectid = $object; // $objectid can be X or 'X,Y,Z'
653  }
654 
655  //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename, $feature2, $dbt_socfield, $dbt_select, $isdraft");
656  //print "user_id=".$user->id.", features=".join(',', $featuresarray).", feature2=".$feature2.", objectid=".$objectid;
657  //print ", tableandshare=".$tableandshare.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select."<br>";
658 
659  // More parameters
660  $params = explode('&', $tableandshare);
661  $dbtablename = (!empty($params[0]) ? $params[0] : '');
662  $sharedelement = (!empty($params[1]) ? $params[1] : $dbtablename);
663 
664  foreach ($featuresarray as $feature) {
665  $sql = '';
666 
667  //var_dump($feature);exit;
668 
669  // For backward compatibility
670  if ($feature == 'member') {
671  $feature = 'adherent';
672  }
673  if ($feature == 'project') {
674  $feature = 'projet';
675  }
676  if ($feature == 'task') {
677  $feature = 'projet_task';
678  }
679 
680  $checkonentitydone = 0;
681 
682  // Array to define rules of checks to do
683  $check = array('adherent', 'banque', 'bom', 'don', 'mrp', 'user', 'usergroup', 'payment', 'payment_supplier', 'product', 'produit', 'service', 'produit|service', 'categorie', 'resource', 'expensereport', 'holiday', 'salaries', 'website', 'recruitment'); // Test on entity only (Objects with no link to company)
684  $checksoc = array('societe'); // Test for societe object
685  $checkother = array('contact', 'agenda', 'contrat'); // Test on entity + link to third party on field $dbt_keyfield. Allowed if link is empty (Ex: contacts...).
686  $checkproject = array('projet', 'project'); // Test for project object
687  $checktask = array('projet_task'); // Test for task object
688  $checkhierarchy = array('expensereport', 'holiday');
689  $nocheck = array('barcode', 'stock'); // No test
690  //$checkdefault = 'all other not already defined'; // Test on entity + link to third party on field $dbt_keyfield. Not allowed if link is empty (Ex: invoice, orders...).
691 
692  // If dbtablename not defined, we use same name for table than module name
693  if (empty($dbtablename)) {
694  $dbtablename = $feature;
695  $sharedelement = (!empty($params[1]) ? $params[1] : $dbtablename); // We change dbtablename, so we set sharedelement too.
696  }
697 
698  // Check permission for object on entity only
699  if (in_array($feature, $check)) {
700  $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
701  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
702  if (($feature == 'user' || $feature == 'usergroup') && !empty($conf->multicompany->enabled)) { // Special for multicompany
703  if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
704  if ($conf->entity == 1 && $user->admin && !$user->entity) {
705  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
706  $sql .= " AND dbt.entity IS NOT NULL";
707  } else {
708  $sql .= ",".MAIN_DB_PREFIX."usergroup_user as ug";
709  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
710  $sql .= " AND ((ug.fk_user = dbt.rowid";
711  $sql .= " AND ug.entity IN (".getEntity('usergroup')."))";
712  $sql .= " OR dbt.entity = 0)"; // Show always superadmin
713  }
714  } else {
715  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
716  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
717  }
718  } else {
719  $reg = array();
720  if ($parenttableforentity && preg_match('/(.*)@(.*)/', $parenttableforentity, $reg)) {
721  $sql .= ", ".MAIN_DB_PREFIX.$reg[2]." as dbtp";
722  $sql .= " WHERE dbt.".$reg[1]." = dbtp.rowid AND dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
723  $sql .= " AND dbtp.entity IN (".getEntity($sharedelement, 1).")";
724  } else {
725  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
726  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
727  }
728  }
729  $checkonentitydone = 1;
730  }
731  if (in_array($feature, $checksoc)) { // We check feature = checksoc
732  // If external user: Check permission for external users
733  if ($user->socid > 0) {
734  if ($user->socid != $objectid) {
735  return false;
736  }
737  } elseif (!empty($conf->societe->enabled) && ($user->rights->societe->lire && empty($user->rights->societe->client->voir))) {
738  // If internal user: Check permission for internal users that are restricted on their objects
739  $sql = "SELECT COUNT(sc.fk_soc) as nb";
740  $sql .= " FROM (".MAIN_DB_PREFIX."societe_commerciaux as sc";
741  $sql .= ", ".MAIN_DB_PREFIX."societe as s)";
742  $sql .= " WHERE sc.fk_soc IN (".$db->sanitize($objectid, 1).")";
743  $sql .= " AND sc.fk_user = ".((int) $user->id);
744  $sql .= " AND sc.fk_soc = s.rowid";
745  $sql .= " AND s.entity IN (".getEntity($sharedelement, 1).")";
746  } elseif (!empty($conf->multicompany->enabled)) {
747  // If multicompany and internal users with all permissions, check user is in correct entity
748  $sql = "SELECT COUNT(s.rowid) as nb";
749  $sql .= " FROM ".MAIN_DB_PREFIX."societe as s";
750  $sql .= " WHERE s.rowid IN (".$db->sanitize($objectid, 1).")";
751  $sql .= " AND s.entity IN (".getEntity($sharedelement, 1).")";
752  }
753 
754  $checkonentitydone = 1;
755  }
756  if (in_array($feature, $checkother)) { // Test on entity + link to thirdparty. Allowed if link is empty (Ex: contacts...).
757  // If external user: Check permission for external users
758  if ($user->socid > 0) {
759  $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
760  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
761  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
762  $sql .= " AND dbt.fk_soc = ".((int) $user->socid);
763  } elseif (!empty($conf->societe->enabled) && ($user->rights->societe->lire && empty($user->rights->societe->client->voir))) {
764  // If internal user: Check permission for internal users that are restricted on their objects
765  $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
766  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
767  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON dbt.fk_soc = sc.fk_soc AND sc.fk_user = ".((int) $user->id);
768  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
769  $sql .= " AND (dbt.fk_soc IS NULL OR sc.fk_soc IS NOT NULL)"; // Contact not linked to a company or to a company of user
770  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
771  } elseif (!empty($conf->multicompany->enabled)) {
772  // If multicompany and internal users with all permissions, check user is in correct entity
773  $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
774  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
775  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
776  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
777  }
778 
779  $checkonentitydone = 1;
780  }
781  if (in_array($feature, $checkproject)) {
782  if (!empty($conf->project->enabled) && empty($user->rights->projet->all->lire)) {
783  $projectid = $objectid;
784 
785  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
786  $projectstatic = new Project($db);
787  $tmps = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, 0);
788 
789  $tmparray = explode(',', $tmps);
790  if (!in_array($projectid, $tmparray)) {
791  return false;
792  }
793  } else {
794  $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
795  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
796  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
797  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
798  }
799 
800  $checkonentitydone = 1;
801  }
802  if (in_array($feature, $checktask)) {
803  if (!empty($conf->project->enabled) && empty($user->rights->projet->all->lire)) {
804  $task = new Task($db);
805  $task->fetch($objectid);
806  $projectid = $task->fk_project;
807 
808  include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
809  $projectstatic = new Project($db);
810  $tmps = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, 0);
811 
812  $tmparray = explode(',', $tmps);
813  if (!in_array($projectid, $tmparray)) {
814  return false;
815  }
816  } else {
817  $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
818  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
819  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
820  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
821  }
822 
823  $checkonentitydone = 1;
824  }
825  if (!$checkonentitydone && !in_array($feature, $nocheck)) { // By default (case of $checkdefault), we check on object entity + link to third party on field $dbt_keyfield
826  // If external user: Check permission for external users
827  if ($user->socid > 0) {
828  if (empty($dbt_keyfield)) {
829  dol_print_error('', 'Param dbt_keyfield is required but not defined');
830  }
831  $sql = "SELECT COUNT(dbt.".$dbt_keyfield.") as nb";
832  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
833  $sql .= " WHERE dbt.rowid IN (".$db->sanitize($objectid, 1).")";
834  $sql .= " AND dbt.".$dbt_keyfield." = ".((int) $user->socid);
835  } elseif (!empty($conf->societe->enabled) && empty($user->rights->societe->client->voir)) {
836  // If internal user: Check permission for internal users that are restricted on their objects
837  if ($feature != 'ticket') {
838  if (empty($dbt_keyfield)) {
839  dol_print_error('', 'Param dbt_keyfield is required but not defined');
840  }
841  $sql = "SELECT COUNT(sc.fk_soc) as nb";
842  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
843  $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc";
844  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
845  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
846  $sql .= " AND sc.fk_soc = dbt.".$dbt_keyfield;
847  $sql .= " AND sc.fk_user = ".((int) $user->id);
848  } else {
849  // On ticket, the thirdparty is not mandatory, so we need a special test to accept record with no thirdparties.
850  $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
851  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
852  $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = dbt.".$dbt_keyfield." AND sc.fk_user = ".((int) $user->id);
853  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
854  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
855  $sql .= " AND (sc.fk_user = ".((int) $user->id)." OR sc.fk_user IS NULL)";
856  }
857  } elseif (!empty($conf->multicompany->enabled)) {
858  // If multicompany and internal users with all permissions, check user is in correct entity
859  $sql = "SELECT COUNT(dbt.".$dbt_select.") as nb";
860  $sql .= " FROM ".MAIN_DB_PREFIX.$dbtablename." as dbt";
861  $sql .= " WHERE dbt.".$dbt_select." IN (".$db->sanitize($objectid, 1).")";
862  $sql .= " AND dbt.entity IN (".getEntity($sharedelement, 1).")";
863  }
864  }
865  //print $sql;
866 
867  // For events, check on users assigned to event
868  if ($feature === 'agenda') {
869  // Also check owner or attendee for users without allactions->read
870  if ($objectid > 0 && empty($user->rights->agenda->allactions->read)) {
871  require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
872  $action = new ActionComm($db);
873  $action->fetch($objectid);
874  if ($action->authorid != $user->id && $action->userownerid != $user->id && !(array_key_exists($user->id, $action->userassigned))) {
875  return false;
876  }
877  }
878  }
879 
880  // For some object, we also have to check it is in the user hierarchy
881  // Param $object must be the full object and not a simple id to have this test possible.
882  if (in_array($feature, $checkhierarchy) && is_object($object)) {
883  $childids = $user->getAllChildIds(1);
884  $useridtocheck = 0;
885  if ($feature == 'holiday') {
886  $useridtocheck = $object->fk_user;
887  if (!in_array($useridtocheck, $childids)) {
888  return false;
889  }
890  $useridtocheck = $object->fk_validator;
891  if (!in_array($useridtocheck, $childids)) {
892  return false;
893  }
894  }
895  if ($feature == 'expensereport') {
896  $useridtocheck = $object->fk_user_author;
897  if (!$user->rights->expensereport->readall) {
898  if (!in_array($useridtocheck, $childids)) {
899  return false;
900  }
901  }
902  }
903  }
904 
905  if ($sql) {
906  $resql = $db->query($sql);
907  if ($resql) {
908  $obj = $db->fetch_object($resql);
909  if (!$obj || $obj->nb < count(explode(',', $objectid))) { // error if we found 0 or less record than nb of id provided
910  return false;
911  }
912  } else {
913  dol_syslog("Bad forged sql in checkUserAccessToObject", LOG_WARNING);
914  return false;
915  }
916  }
917  }
918 
919  return true;
920 }
921 
933 function accessforbidden($message = '', $printheader = 1, $printfooter = 1, $showonlymessage = 0, $params = null)
934 {
935  global $conf, $db, $user, $langs, $hookmanager;
936  if (!is_object($langs)) {
937  include_once DOL_DOCUMENT_ROOT.'/core/class/translate.class.php';
938  $langs = new Translate('', $conf);
939  $langs->setDefaultLang();
940  }
941 
942  $langs->load("errors");
943 
944  if ($printheader) {
945  if (function_exists("llxHeader")) {
946  llxHeader('');
947  } elseif (function_exists("llxHeaderVierge")) {
948  llxHeaderVierge('');
949  }
950  }
951  print '<div class="error">';
952  if (!$message) {
953  print $langs->trans("ErrorForbidden");
954  } else {
955  print $message;
956  }
957  print '</div>';
958  print '<br>';
959  if (empty($showonlymessage)) {
960  global $action, $object;
961  if (empty($hookmanager)) {
962  $hookmanager = new HookManager($db);
963  // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context
964  $hookmanager->initHooks(array('main'));
965  }
966  $parameters = array('message'=>$message, 'params'=>$params);
967  $reshook = $hookmanager->executeHooks('getAccessForbiddenMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks
968  print $hookmanager->resPrint;
969  if (empty($reshook)) {
970  $langs->loadLangs(array("errors"));
971  if ($user->login) {
972  print $langs->trans("CurrentLogin").': <span class="error">'.$user->login.'</span><br>';
973  print $langs->trans("ErrorForbidden2", $langs->transnoentitiesnoconv("Home"), $langs->transnoentitiesnoconv("Users"));
974  print $langs->trans("ErrorForbidden4");
975  } else {
976  print $langs->trans("ErrorForbidden3");
977  }
978  }
979  }
980  if ($printfooter && function_exists("llxFooter")) {
981  llxFooter();
982  }
983  exit(0);
984 }
985 
986 
994 {
995  global $conf;
996 
997  $max = $conf->global->MAIN_UPLOAD_DOC; // In Kb
998  $maxphp = @ini_get('upload_max_filesize'); // In unknown
999  if (preg_match('/k$/i', $maxphp)) {
1000  $maxphp = preg_replace('/k$/i', '', $maxphp);
1001  $maxphp = $maxphp * 1;
1002  }
1003  if (preg_match('/m$/i', $maxphp)) {
1004  $maxphp = preg_replace('/m$/i', '', $maxphp);
1005  $maxphp = $maxphp * 1024;
1006  }
1007  if (preg_match('/g$/i', $maxphp)) {
1008  $maxphp = preg_replace('/g$/i', '', $maxphp);
1009  $maxphp = $maxphp * 1024 * 1024;
1010  }
1011  if (preg_match('/t$/i', $maxphp)) {
1012  $maxphp = preg_replace('/t$/i', '', $maxphp);
1013  $maxphp = $maxphp * 1024 * 1024 * 1024;
1014  }
1015  $maxphp2 = @ini_get('post_max_size'); // In unknown
1016  if (preg_match('/k$/i', $maxphp2)) {
1017  $maxphp2 = preg_replace('/k$/i', '', $maxphp2);
1018  $maxphp2 = $maxphp2 * 1;
1019  }
1020  if (preg_match('/m$/i', $maxphp2)) {
1021  $maxphp2 = preg_replace('/m$/i', '', $maxphp2);
1022  $maxphp2 = $maxphp2 * 1024;
1023  }
1024  if (preg_match('/g$/i', $maxphp2)) {
1025  $maxphp2 = preg_replace('/g$/i', '', $maxphp2);
1026  $maxphp2 = $maxphp2 * 1024 * 1024;
1027  }
1028  if (preg_match('/t$/i', $maxphp2)) {
1029  $maxphp2 = preg_replace('/t$/i', '', $maxphp2);
1030  $maxphp2 = $maxphp2 * 1024 * 1024 * 1024;
1031  }
1032  // Now $max and $maxphp and $maxphp2 are in Kb
1033  $maxmin = $max;
1034  $maxphptoshow = $maxphptoshowparam = '';
1035  if ($maxphp > 0) {
1036  $maxmin = min($maxmin, $maxphp);
1037  $maxphptoshow = $maxphp;
1038  $maxphptoshowparam = 'upload_max_filesize';
1039  }
1040  if ($maxphp2 > 0) {
1041  $maxmin = min($maxmin, $maxphp2);
1042  if ($maxphp2 < $maxphp) {
1043  $maxphptoshow = $maxphp2;
1044  $maxphptoshowparam = 'post_max_size';
1045  }
1046  }
1047  //var_dump($maxphp.'-'.$maxphp2);
1048  //var_dump($maxmin);
1049 
1050  return array('max'=>$max, 'maxmin'=>$maxmin, 'maxphptoshow'=>$maxphptoshow, 'maxphptoshowparam'=>$maxphptoshowparam);
1051 }
restrictedArea
restrictedArea($user, $features, $objectid=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $mode=0)
Check permissions of a user to show a page and an object.
Definition: security.lib.php:234
llxFooter
llxFooter()
Empty footer.
Definition: wrapper.php:73
Project
Class to manage projects.
Definition: project.class.php:35
ActionComm
Class to manage agenda events (actions)
Definition: actioncomm.class.php:38
GETPOST
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
Definition: functions.lib.php:484
dol_print_error
dol_print_error($db='', $error='', $errors=null)
Displays error message system with all the information to facilitate the diagnosis and the escalation...
Definition: functions.lib.php:4844
dol_verifyHash
dol_verifyHash($chain, $hash, $type='0')
Compute a hash and compare it to the given one For backward compatibility reasons,...
Definition: security.lib.php:151
Translate
Class to manage translations.
Definition: translate.class.php:30
Task
Class to manage tasks.
Definition: task.class.php:37
llxHeaderVierge
if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) if(!defined('NOLOGIN')) if(!defined('NOCSRFCHECK')) if(!defined('NOIPCHECK')) llxHeaderVierge()
Header function.
Definition: agendaexport.php:61
dolGetLdapPasswordHash
dolGetLdapPasswordHash($password, $type='md5')
Returns a specific ldap hash of a password.
Definition: security.lib.php:177
dol_hash
dol_hash($chain, $type='0')
Returns a hash of a string.
Definition: security.lib.php:104
getMaxFileSizeArray
getMaxFileSizeArray()
Return the max allowed for file upload.
Definition: security.lib.php:993
dol_syslog
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
Definition: functions.lib.php:1603
getDolGlobalString
if(!function_exists('utf8_encode')) if(!function_exists('utf8_decode')) getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
Definition: functions.lib.php:80
dol_strlen
dol_strlen($string, $stringencoding='UTF-8')
Make a strlen call.
Definition: functions.lib.php:3747
dol_encode
dol_encode($chain, $key='1')
Encode a string with base 64 algorithm + specific delta change.
Definition: security.lib.php:38
$resql
if(isModEnabled('facture') &&!empty($user->rights->facture->lire)) if((isModEnabled('fournisseur') &&empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD) && $user->rights->fournisseur->facture->lire)||(isModEnabled('supplier_invoice') && $user->rights->supplier_invoice->lire)) if(isModEnabled('don') &&!empty($user->rights->don->lire)) if(isModEnabled('tax') &&!empty($user->rights->tax->charges->lire)) if(isModEnabled('facture') &&isModEnabled('commande') && $user->rights->commande->lire &&empty($conf->global->WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER)) $resql
Social contributions to pay.
Definition: index.php:742
checkUserAccessToObject
checkUserAccessToObject($user, array $featuresarray, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='', $dbt_select='rowid', $parenttableforentity='')
Check that access by a given user to an object is ok.
Definition: security.lib.php:645
accessforbidden
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program Calling this function terminate execution ...
Definition: security.lib.php:933
llxHeader
if(!defined('NOREQUIRESOC')) if(!defined('NOREQUIRETRAN')) if(!defined('NOCSRFCHECK')) if(!defined('NOTOKENRENEWAL')) if(!defined('NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined('NOREQUIREAJAX')) llxHeader()
Empty header.
Definition: wrapper.php:59
HookManager
Class to manage hooks.
Definition: hookmanager.class.php:30
dol_decode
dol_decode($chain, $key='1')
Decode a base 64 encoded + specific delta change.
Definition: security.lib.php:69