PageRenderTime 47ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/htdocs/core/lib/security.lib.php

https://bitbucket.org/speedealing/speedealing
PHP | 443 lines | 311 code | 31 blank | 101 comment | 206 complexity | e73f1be304c561361674c6572f7a5c3d MD5 | raw file
Possible License(s): LGPL-3.0, LGPL-2.1, GPL-3.0, MIT
  1. <?php
  2. /* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2008-2012 Regis Houssin <regis.houssin@capnetworks.com>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 3 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. * or see http://www.gnu.org/
  18. */
  19. /**
  20. * \file htdocs/core/lib/security.lib.php
  21. * \ingroup core
  22. * \brief Set of function used for dolibarr security (common function included into filefunc.inc.php)
  23. * Warning, this file must not depends on other library files, except function.lib.php
  24. * because it is used at low code level.
  25. */
  26. /**
  27. * Encode a string with base 64 algorithm + specific change
  28. * Code of this function is useless and we should use base64_encode only instead
  29. *
  30. * @param string $chain string to encode
  31. * @return string encoded string
  32. */
  33. function dol_encode($chain) {
  34. $strlength = dol_strlen($chain);
  35. for ($i = 0; $i < $strlength; $i++) {
  36. $output_tab[$i] = chr(ord(substr($chain, $i, 1)) + 17);
  37. }
  38. $string_coded = base64_encode(implode("", $output_tab));
  39. return $string_coded;
  40. }
  41. /**
  42. * Decode a base 64 encoded + specific string.
  43. * This function is called by filefunc.inc.php at each page call.
  44. * Code of this function is useless and we should use base64_decode only instead
  45. *
  46. * @param string $chain string to decode
  47. * @return string decoded string
  48. */
  49. function dol_decode($chain) {
  50. $chain = base64_decode($chain);
  51. $strlength = dol_strlen($chain);
  52. for ($i = 0; $i < $strlength; $i++) {
  53. $output_tab[$i] = chr(ord(substr($chain, $i, 1)) - 17);
  54. }
  55. $string_decoded = implode("", $output_tab);
  56. return $string_decoded;
  57. }
  58. /**
  59. * Returns a hash of a string
  60. *
  61. * @param string $chain String to hash
  62. * @param int $type Type of hash (0:md5, 1:sha1, 2:sha1+md5)
  63. * @return string Hash of string
  64. */
  65. function dol_hash($chain, $type = 0) {
  66. if ($type == 1)
  67. return sha1($chain);
  68. else if ($type == 2)
  69. return sha1(md5($chain));
  70. else
  71. return md5($chain);
  72. }
  73. /**
  74. * Check permissions of a user to show a page and an object. Check read permission.
  75. * If GETPOST('action') defined, we also check write and delete permission.
  76. *
  77. * @param User $user User to check
  78. * @param string $features Features to check (in most cases, it's module name. Examples: 'societe', 'contact', 'produit|service', ...)
  79. * @param int $objectid Object ID if we want to check a particular record (optionnal) is linked to a owned thirdparty (optionnal).
  80. * @param string $dbtablename 'TableName&SharedElement' with Tablename is table where object is stored, SharedElement is key to define where to check entity. Not used if objectid is null (optionnal)
  81. * @param string $feature2 Feature to check, second level of permission (optionnal)
  82. * @param string $dbt_keyfield Field name for socid foreign key if not fk_soc (optionnal)
  83. * @param string $dbt_select Field name for select if not rowid (optionnal)
  84. * @param Canvas $objcanvas Object canvas
  85. * @return int Always 1, die process if not allowed
  86. */
  87. function restrictedArea($user, $features, $objectid = 0, $dbtablename = '', $feature2 = '', $dbt_keyfield = 'fk_soc', $dbt_select = 'rowid', $objcanvas = null) {
  88. global $db, $conf;
  89. //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename,$feature2,$dbt_socfield,$dbt_select");
  90. //print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid;
  91. //print ", dbtablename=".$dbtablename.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select;
  92. //print ", perm: ".$features."->".$feature2."=".$user->rights->$features->$feature2->lire."<br>";
  93. // If we use canvas, we try to use function that overlod restrictarea if provided with canvas
  94. if (is_object($objcanvas)) {
  95. if (method_exists($objcanvas->control, 'restrictedArea'))
  96. return $objcanvas->control->restrictedArea($user, $features, $objectid, $dbtablename, $feature2, $dbt_keyfield, $dbt_select);
  97. }
  98. if ($dbt_select != 'rowid')
  99. $objectid = "'" . $objectid . "'";
  100. // More features to check
  101. $features = explode("&", $features);
  102. // More parameters
  103. $params = explode('&', $dbtablename);
  104. $dbtablename = (!empty($params[0]) ? $params[0] : '');
  105. $sharedelement = (!empty($params[1]) ? $params[1] : '');
  106. // Check read permission from module
  107. // TODO Replace "feature" param into caller by first level of permission
  108. $readok = 1;
  109. foreach ($features as $feature) {
  110. if ($feature == 'societe') {
  111. if (!$user->rights->societe->lire && !$user->rights->fournisseur->lire)
  112. $readok = 0;
  113. }
  114. else if ($feature == 'contact') {
  115. if (!$user->rights->societe->contact->lire)
  116. $readok = 0;
  117. }
  118. else if ($feature == 'produit|service') {
  119. if (!$user->rights->produit->lire && !$user->rights->service->lire)
  120. $readok = 0;
  121. }
  122. else if ($feature == 'prelevement') {
  123. if (!$user->rights->prelevement->bons->lire)
  124. $readok = 0;
  125. }
  126. else if ($feature == 'commande_fournisseur') {
  127. if (!$user->rights->fournisseur->commande->lire)
  128. $readok = 0;
  129. }
  130. else if ($feature == 'cheque') {
  131. if (!$user->rights->banque->cheque)
  132. $readok = 0;
  133. }
  134. else if ($feature == 'projet') {
  135. if (!$user->rights->projet->lire && !$user->rights->projet->all->lire)
  136. $readok = 0;
  137. }
  138. else if (!empty($feature2)) { // This should be used for future changes
  139. if (empty($user->rights->$feature->$feature2->lire)
  140. && empty($user->rights->$feature->$feature2->read))
  141. $readok = 0;
  142. }
  143. else if (!empty($feature) && ($feature != 'user' && $feature != 'usergroup')) { // This is for old permissions
  144. if (empty($user->rights->$feature->lire)
  145. && empty($user->rights->$feature->read)
  146. && empty($user->rights->$feature->run))
  147. $readok = 0;
  148. }
  149. }
  150. if ($user->admin)
  151. return 1;
  152. //print $readok;
  153. if (!$readok)
  154. accessforbidden();
  155. //print "Read access is ok";
  156. // Check write permission from module
  157. $createok = 1;
  158. if (GETPOST("action") == 'create') {
  159. foreach ($features as $feature) {
  160. if ($feature == 'contact') {
  161. if (!$user->rights->societe->contact->creer)
  162. $createok = 0;
  163. }
  164. else if ($feature == 'produit|service') {
  165. if (!$user->rights->produit->creer && !$user->rights->service->creer)
  166. $createok = 0;
  167. }
  168. else if ($feature == 'prelevement') {
  169. if (!$user->rights->prelevement->bons->creer)
  170. $createok = 0;
  171. }
  172. else if ($feature == 'commande_fournisseur') {
  173. if (!$user->rights->fournisseur->commande->creer)
  174. $createok = 0;
  175. }
  176. else if ($feature == 'banque') {
  177. if (!$user->rights->banque->modifier)
  178. $createok = 0;
  179. }
  180. else if ($feature == 'cheque') {
  181. if (!$user->rights->banque->cheque)
  182. $createok = 0;
  183. }
  184. else if (!empty($feature2)) { // This should be used for future changes
  185. if (empty($user->rights->$feature->$feature2->creer)
  186. && empty($user->rights->$feature->$feature2->write))
  187. $createok = 0;
  188. }
  189. else if (!empty($feature)) { // This is for old permissions
  190. //print '<br>feature='.$feature.' creer='.$user->rights->$feature->creer.' write='.$user->rights->$feature->write;
  191. if (empty($user->rights->$feature->creer)
  192. && empty($user->rights->$feature->write))
  193. $createok = 0;
  194. }
  195. }
  196. if ($user->admin)
  197. $createok = 1;
  198. if (!$createok)
  199. accessforbidden();
  200. //print "Write access is ok";
  201. }
  202. // Check create user permission
  203. $createuserok = 1;
  204. if (GETPOST("action") == 'confirm_create_user' && GETPOST("confirm") == 'yes') {
  205. if (!$user->rights->user->user->creer)
  206. $createuserok = 0;
  207. if (!$createuserok)
  208. accessforbidden();
  209. //print "Create user access is ok";
  210. }
  211. // Check delete permission from module
  212. $deleteok = 1;
  213. if ((GETPOST("action") == 'confirm_delete' && GETPOST("confirm") == 'yes') || GETPOST("action") == 'delete') {
  214. foreach ($features as $feature) {
  215. if ($feature == 'contact') {
  216. if (!$user->rights->societe->contact->supprimer)
  217. $deleteok = 0;
  218. }
  219. else if ($feature == 'produit|service') {
  220. if (!$user->rights->produit->supprimer && !$user->rights->service->supprimer)
  221. $deleteok = 0;
  222. }
  223. else if ($feature == 'commande_fournisseur') {
  224. if (!$user->rights->fournisseur->commande->supprimer)
  225. $deleteok = 0;
  226. }
  227. else if ($feature == 'banque') {
  228. if (!$user->rights->banque->modifier)
  229. $deleteok = 0;
  230. }
  231. else if ($feature == 'cheque') {
  232. if (!$user->rights->banque->cheque)
  233. $deleteok = 0;
  234. }
  235. else if ($feature == 'ecm') {
  236. if (!$user->rights->ecm->upload)
  237. $deleteok = 0;
  238. }
  239. else if ($feature == 'ftp') {
  240. if (!$user->rights->ftp->write)
  241. $deleteok = 0;
  242. }
  243. else if (!empty($feature2)) { // This should be used for future changes
  244. if (empty($user->rights->$feature->$feature2->supprimer)
  245. && empty($user->rights->$feature->$feature2->delete))
  246. $deleteok = 0;
  247. }
  248. else if (!empty($feature)) { // This is for old permissions
  249. //print '<br>feature='.$feature.' creer='.$user->rights->$feature->supprimer.' write='.$user->rights->$feature->delete;
  250. if (empty($user->rights->$feature->supprimer)
  251. && empty($user->rights->$feature->delete)
  252. && empty($user->rights->$feature->run))
  253. $deleteok = 0;
  254. }
  255. }
  256. //print "Delete access is ko";
  257. if (!$deleteok)
  258. accessforbidden();
  259. //print "Delete access is ok";
  260. }
  261. // If we have a particular object to check permissions on, we check this object
  262. // is linked to a company allowed to $user.
  263. if (!empty($objectid) && $objectid > 0) {
  264. foreach ($features as $feature) {
  265. $sql = '';
  266. $check = array('adherent', 'banque', 'user', 'usergroup', 'produit', 'service', 'produit|service', 'categorie'); // Test on entity only (Objects with no link to company)
  267. $checksoc = array('societe'); // Test for societe object
  268. $checkother = array('contact'); // Test on entity and link to societe. Allowed if link is empty (Ex: contacts...).
  269. $checkproject = array('projet'); // Test for project object
  270. $nocheck = array('barcode', 'stock', 'fournisseur'); // No test
  271. $checkdefault = 'all other not already defined'; // Test on entity and link to third party. Not allowed if link is empty (Ex: invoice, orders...).
  272. // If dbtable not defined, we use same name for table than module name
  273. if (empty($dbtablename))
  274. $dbtablename = $feature;
  275. // Check permission for object with entity
  276. if (in_array($feature, $check)) {
  277. $sql = "SELECT dbt." . $dbt_select;
  278. $sql.= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
  279. $sql.= " WHERE dbt." . $dbt_select . " = " . $objectid;
  280. if (($feature == 'user' || $feature == 'usergroup') && !empty($conf->multicompany->enabled) && $conf->entity == 1 && $user->admin && !$user->entity) {
  281. $sql.= " AND dbt.entity IS NOT NULL";
  282. } else {
  283. $sql.= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
  284. }
  285. } else if (in_array($feature, $checksoc)) {
  286. // If external user: Check permission for external users
  287. if ($user->societe_id > 0) {
  288. if ($user->societe_id <> $objectid)
  289. accessforbidden();
  290. }
  291. // If internal user: Check permission for internal users that are restricted on their objects
  292. else if (!empty($conf->societe->enabled) && ($user->rights->societe->lire && !$user->rights->societe->client->voir)) {
  293. $object = new Societe($db);
  294. $object->load($objectid);
  295. if ($object->commercial_id->id == $user->id)
  296. $readok = true;
  297. else
  298. $readok = false;
  299. }
  300. } else if (in_array($feature, $checkother)) {
  301. // If external user: Check permission for external users
  302. if ($user->societe_id > 0) {
  303. $sql = "SELECT dbt.rowid";
  304. $sql.= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
  305. $sql.= " WHERE dbt.rowid = " . $objectid;
  306. $sql.= " AND dbt.fk_soc = " . $user->societe_id;
  307. }
  308. // If internal user: Check permission for internal users that are restricted on their objects
  309. else if (!empty($conf->societe->enabled) && ($user->rights->societe->lire && !$user->rights->societe->client->voir)) {
  310. $object = new Societe($db);
  311. $object->load($objectid);
  312. if ($object->commercial_id->id == $user->id)
  313. $readok = true;
  314. else
  315. $readok = false;
  316. }
  317. } else if (in_array($feature, $checkproject)) {
  318. if (!empty($conf->projet->enabled) && !$user->rights->projet->all->lire) {
  319. include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
  320. $projectstatic = new Project($db);
  321. $tmps = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, 0);
  322. $tmparray = explode(',', $tmps);
  323. if (!in_array($objectid, $tmparray))
  324. accessforbidden();
  325. }
  326. else {
  327. $sql = "SELECT dbt." . $dbt_select;
  328. $sql.= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
  329. $sql.= " WHERE dbt." . $dbt_select . " = " . $objectid;
  330. $sql.= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
  331. }
  332. } else if (!in_array($feature, $nocheck)) { // By default we check with link to third party
  333. // If external user: Check permission for external users
  334. if ($user->societe_id > 0) {
  335. $sql = "SELECT dbt." . $dbt_keyfield;
  336. $sql.= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
  337. $sql.= " WHERE dbt.rowid = " . $objectid;
  338. $sql.= " AND dbt." . $dbt_keyfield . " = " . $user->societe_id;
  339. }
  340. // If internal user: Check permission for internal users that are restricted on their objects
  341. else if (!empty($conf->societe->enabled) && ($user->rights->societe->lire && !$user->rights->societe->client->voir)) {
  342. $sql = "SELECT sc.fk_soc";
  343. $sql.= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
  344. $sql.= ", " . MAIN_DB_PREFIX . "societe as s";
  345. $sql.= ", " . MAIN_DB_PREFIX . "societe_commerciaux as sc";
  346. $sql.= " WHERE dbt." . $dbt_select . " = " . $objectid;
  347. $sql.= " AND sc.fk_soc = dbt." . $dbt_keyfield;
  348. $sql.= " AND dbt." . $dbt_keyfield . " = s.rowid";
  349. $sql.= " AND s.entity IN (" . getEntity($sharedelement, 1) . ")";
  350. $sql.= " AND sc.fk_user = " . $user->id;
  351. }
  352. }
  353. //print $sql."<br>";
  354. if ($sql) {
  355. $resql = $db->query($sql);
  356. if ($resql) {
  357. if ($db->num_rows($resql) == 0)
  358. accessforbidden();
  359. }
  360. else {
  361. dol_syslog("security.lib:restrictedArea sql=" . $sql, LOG_ERR);
  362. accessforbidden();
  363. }
  364. } else if (!$readok)
  365. accessforbidden();
  366. }
  367. }
  368. return 1;
  369. }
  370. /**
  371. * Show a message to say access is forbidden and stop program
  372. * Calling this function terminate execution of PHP.
  373. *
  374. * @param string $message Force error message
  375. * @param int $printheader Show header before
  376. * @param int $printfooter Show footer after
  377. * @param int $showonlymessage Show only message parameter. Otherwise add more information.
  378. * @return void
  379. */
  380. function accessforbidden($message = '', $printheader = 1, $printfooter = 1, $showonlymessage = 0) {
  381. global $conf, $db, $user, $langs;
  382. if (!is_object($langs)) {
  383. include_once DOL_DOCUMENT_ROOT . '/core/class/translate.class.php';
  384. $langs = new Translate();
  385. }
  386. $langs->load("errors");
  387. if ($printheader) {
  388. if (function_exists("llxHeader"))
  389. llxHeader('');
  390. else if (function_exists("llxHeaderVierge"))
  391. llxHeaderVierge('');
  392. }
  393. print '<div class="error">';
  394. if (!$message)
  395. print $langs->trans("ErrorForbidden");
  396. else
  397. print $message;
  398. print '</div>';
  399. print '<br>';
  400. if (empty($showonlymessage)) {
  401. if ($user->name) {
  402. print $langs->trans("CurrentLogin") . ': <font class="error">' . $user->login . '</font><br>';
  403. print $langs->trans("ErrorForbidden2", $langs->trans("Home"), $langs->trans("Users"));
  404. } else {
  405. print $langs->trans("ErrorForbidden3");
  406. }
  407. }
  408. if ($printfooter && function_exists("llxFooter"))
  409. llxFooter();
  410. exit;
  411. }
  412. ?>