Passed
Push — master ( 65bdac...4e88da )
by Alxarafe
32:38
created

Security::checkUserAccessToObject()   F

Complexity

Conditions 50
Paths 9124

Size

Total Lines 183
Code Lines 139

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 50
eloc 139
nc 9124
nop 7
dl 0
loc 183
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
/* Copyright (C) 2008-2011 Laurent Destailleur  <[email protected]>
3
 * Copyright (C) 2008-2017 Regis Houssin        <[email protected]>
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
namespace Alixar\Helpers;
20
21
/**
22
 *  \file		htdocs/core/lib/security.lib.php
23
 *  \ingroup    core
24
 *  \brief		Set of function used for dolibarr security (common function included into filefunc.inc.php)
25
 *  			Warning, this file must not depends on other library files, except function.lib.php
26
 *  			because it is used at low code level.
27
 */
28
class Security
29
{
30
31
    /**
32
     * 	Encode a string with base 64 algorithm + specific delta change.
33
     *
34
     * 	@param   string		$chain		string to encode
35
     * 	@param   string		$key		rule to use for delta ('0', '1' or 'myownkey')
36
     * 	@return  string					encoded string
37
     *  @see dol_decode
38
     */
39
    function dol_encode($chain, $key = '1')
40
    {
41
        if (is_numeric($key) && $key == '1') { // rule 1 is offset of 17 for char
42
            $output_tab = array();
43
            $strlength = dol_strlen($chain);
44
            for ($i = 0; $i < $strlength; $i++) {
45
                $output_tab[$i] = chr(ord(substr($chain, $i, 1)) + 17);
46
            }
47
            $chain = implode("", $output_tab);
48
        } elseif ($key) {
49
            $result = '';
50
            $strlength = dol_strlen($chain);
51
            for ($i = 0; $i < $strlength; $i++) {
52
                $keychar = substr($key, ($i % strlen($key)) - 1, 1);
53
                $result .= chr(ord(substr($chain, $i, 1)) + (ord($keychar) - 65));
54
            }
55
            $chain = $result;
56
        }
57
58
        return base64_encode($chain);
59
    }
60
61
    /**
62
     * 	Decode a base 64 encoded + specific delta change.
63
     *  This function is called by filefunc.inc.php at each page call.
64
     *
65
     * 	@param   string		$chain		string to decode
66
     * 	@param   string		$key		rule to use for delta ('0', '1' or 'myownkey')
67
     * 	@return  string					decoded string
68
     *  @see dol_encode
69
     */
70
    function dol_decode($chain, $key = '1')
71
    {
72
        $chain = base64_decode($chain);
73
74
        if (is_numeric($key) && $key == '1') { // rule 1 is offset of 17 for char
75
            $output_tab = array();
76
            $strlength = dol_strlen($chain);
77
            for ($i = 0; $i < $strlength; $i++) {
78
                $output_tab[$i] = chr(ord(substr($chain, $i, 1)) - 17);
79
            }
80
81
            $chain = implode("", $output_tab);
82
        } elseif ($key) {
83
            $result = '';
84
            $strlength = dol_strlen($chain);
85
            for ($i = 0; $i < $strlength; $i++) {
86
                $keychar = substr($key, ($i % strlen($key)) - 1, 1);
87
                $result .= chr(ord(substr($chain, $i, 1)) - (ord($keychar) - 65));
88
            }
89
            $chain = $result;
90
        }
91
92
        return $chain;
93
    }
94
95
    /**
96
     * 	Returns a hash of a string.
97
     *  If constant MAIN_SECURITY_HASH_ALGO is defined, we use this function as hashing function (recommanded value is 'password_hash')
98
     *  If constant MAIN_SECURITY_SALT is defined, we use it as a salt (used only if hashing algorightm is something else than 'password_hash').
99
     *
100
     * 	@param 		string		$chain		String to hash
101
     * 	@param		string		$type		Type of hash ('0':auto will use MAIN_SECURITY_HASH_ALGO else md5, '1':sha1, '2':sha1+md5, '3':md5, '4':md5 for OpenLdap, '5':sha256). Use '3' here, if hash is not needed for security purpose, for security need, prefer '0'.
102
     * 	@return		string					Hash of string
103
     *  @getRandomPassword
104
     */
105
    static function dol_hash($chain, $type = '0')
106
    {
107
        // No need to add salt for password_hash
108
        if (($type == '0' || $type == 'auto') && !empty(Globals::$conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists('password_hash')) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $conf seems to be never defined.
Loading history...
109
            return password_hash($chain, PASSWORD_DEFAULT);
110
        }
111
        // Salt value
112
        if (!empty(Globals::$conf->global->MAIN_SECURITY_SALT)) {
113
            $chain = Globals::$conf->global->MAIN_SECURITY_SALT . $chain;
114
        }
115
        if ($type == '1' || $type == 'sha1') {
116
            return sha1($chain);
117
        }
118
        if ($type == '2' || $type == 'sha1md5') {
119
            return sha1(md5($chain));
120
        }
121
        if ($type == '3' || $type == 'md5') {
122
            return md5($chain);
123
        }
124
        if ($type == '4' || $type == 'md5openldap') {
125
            return '{md5}' . base64_encode(mhash(MHASH_MD5, $chain)); // For OpenLdap with md5 (based on an unencrypted password in base)
126
        }
127
        if ($type == '5') {
128
            return hash('sha256', $chain);
129
        }
130
        if (!empty(Globals::$conf->global->MAIN_SECURITY_HASH_ALGO) && Globals::$conf->global->MAIN_SECURITY_HASH_ALGO == 'sha1') {
131
            return sha1($chain);
132
        }
133
        if (!empty(Globals::$conf->global->MAIN_SECURITY_HASH_ALGO) && Globals::$conf->global->MAIN_SECURITY_HASH_ALGO == 'sha1md5') {
134
            return sha1(md5($chain));
135
        }
136
        // No particular encoding defined, use default
137
        return md5($chain);
138
    }
139
140
    /**
141
     * 	Compute a hash and compare it to the given one
142
     *  For backward compatibility reasons, if the hash is not in the password_hash format, we will try to match against md5 and sha1md5
143
     *  If constant MAIN_SECURITY_HASH_ALGO is defined, we use this function as hashing function.
144
     *  If constant MAIN_SECURITY_SALT is defined, we use it as a salt.
145
     *
146
     * 	@param 		string		$chain		String to hash (not hashed string)
147
     * 	@param 		string		$hash		hash to compare
148
     * 	@param		string		$type		Type of hash ('0':auto, '1':sha1, '2':sha1+md5, '3':md5, '4':md5 for OpenLdap, '5':sha256). Use '3' here, if hash is not needed for security purpose, for security need, prefer '0'.
149
     * 	@return		bool					True if the computed hash is the same as the given one
150
     */
151
    static function dol_verifyHash($chain, $hash, $type = '0')
152
    {
153
        return \password_verify($chain, $hash);
154
155
        if ($type == '0' && !empty($conf->global->MAIN_SECURITY_HASH_ALGO) && $conf->global->MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists('password_verify')) {
0 ignored issues
show
Unused Code introduced by
IfNode is not reachable.

This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.

Unreachable code is most often the result of return, die or exit statements that have been added for debug purposes.

function fx() {
    try {
        doSomething();
        return true;
    }
    catch (\Exception $e) {
        return false;
    }

    return false;
}

In the above example, the last return false will never be executed, because a return statement has already been met in every possible execution path.

Loading history...
156
            if ($hash[0] == '$') {
157
                return \password_verify($chain, $hash);
158
            }
159
            if (strlen($hash) == 32) {
160
                return self::dol_verifyHash($chain, $hash, '3'); // md5
161
            }
162
            if (strlen($hash) == 40) {
163
                return self::dol_verifyHash($chain, $hash, '2'); // sha1md5
164
            }
165
166
            return false;
167
        }
168
169
        return self::dol_hash($chain, $type) == $hash;
170
    }
171
172
    /**
173
     * 	Check permissions of a user to show a page and an object. Check read permission.
174
     * 	If GETPOST('action','aZ09') defined, we also check write and delete permission.
175
     *
176
     * 	@param	User	$user      	  	User to check
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\User was not found. Did you mean User? If so, make sure to prefix the type with \.
Loading history...
177
     * 	@param  string	$features	    Features to check (it must be module name. Examples: 'societe', 'contact', 'produit&service', 'produit|service', ...)
178
     * 	@param  int		$objectid      	Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional).
179
     * 	@param  string	$tableandshare  'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity for multicompany modume. Param not used if objectid is null (optional).
180
     * 	@param  string	$feature2		Feature to check, second level of permission (optional). Can be a 'or' check with 'level1|level2'.
181
     *  @param  string	$dbt_keyfield   Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional)
182
     *  @param  string	$dbt_select     Field name for select if not rowid. Not used if objectid is null (optional)
183
     *  @param	int		$isdraft		1=The object with id=$objectid is a draft
184
     * 	@return	int						Always 1, die process if not allowed
185
     *  @see dol_check_secure_access_document
186
     */
187
    function restrictedArea($user, $features, $objectid = 0, $tableandshare = '', $feature2 = '', $dbt_keyfield = 'fk_soc', $dbt_select = 'rowid', $isdraft = 0)
188
    {
189
        global $db, $conf;
190
        global $hookmanager;
191
192
        //dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename,$feature2,$dbt_socfield,$dbt_select");
193
        //print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid;
194
        //print ", dbtablename=".$dbtablename.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select;
195
        //print ", perm: ".$features."->".$feature2."=".($user->rights->$features->$feature2->lire)."<br>";
196
        // Get more permissions checks from hooks
197
        $parameters = array('features' => $features, 'objectid' => $objectid, 'idtype' => $dbt_select);
198
        $reshook = $hookmanager->executeHooks('restrictedArea', $parameters);
199
        if (!empty($hookmanager->resArray['result']))
200
            return true;
201
        if ($reshook > 0)
202
            return false;
203
204
        if ($dbt_select != 'rowid' && $dbt_select != 'id')
205
            $objectid = "'" . $objectid . "'";
206
207
        // Features/modules to check
208
        $featuresarray = array($features);
209
        if (preg_match('/&/', $features))
210
            $featuresarray = explode("&", $features);
211
        else if (preg_match('/\|/', $features))
212
            $featuresarray = explode("|", $features);
213
214
        // More subfeatures to check
215
        if (!empty($feature2))
216
            $feature2 = explode("|", $feature2);
217
218
        // More parameters
219
        $params = explode('&', $tableandshare);
220
        $dbtablename = (!empty($params[0]) ? $params[0] : '');
221
        $sharedelement = (!empty($params[1]) ? $params[1] : $dbtablename);
222
223
        $listofmodules = explode(',', $conf->global->MAIN_MODULES_FOR_EXTERNAL);
224
225
        // Check read permission from module
226
        $readok = 1;
227
        $nbko = 0;
228
        foreach ($featuresarray as $feature) { // first we check nb of test ko
229
            $featureforlistofmodule = $feature;
230
            if ($featureforlistofmodule == 'produit')
231
                $featureforlistofmodule = 'product';
232
            if (!empty($user->societe_id) && !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
233
                $readok = 0;
234
                $nbko++;
235
                continue;
236
            }
237
238
            if ($feature == 'societe') {
239
                if (!$user->rights->societe->lire && !$user->rights->fournisseur->lire) {
240
                    $readok = 0;
241
                    $nbko++;
242
                }
243
            } else if ($feature == 'contact') {
244
                if (!$user->rights->societe->contact->lire) {
245
                    $readok = 0;
246
                    $nbko++;
247
                }
248
            } else if ($feature == 'produit|service') {
249
                if (!$user->rights->produit->lire && !$user->rights->service->lire) {
250
                    $readok = 0;
251
                    $nbko++;
252
                }
253
            } else if ($feature == 'prelevement') {
254
                if (!$user->rights->prelevement->bons->lire) {
255
                    $readok = 0;
256
                    $nbko++;
257
                }
258
            } else if ($feature == 'cheque') {
259
                if (!$user->rights->banque->cheque) {
260
                    $readok = 0;
261
                    $nbko++;
262
                }
263
            } else if ($feature == 'projet') {
264
                if (!$user->rights->projet->lire && !$user->rights->projet->all->lire) {
265
                    $readok = 0;
266
                    $nbko++;
267
                }
268
            } else if (!empty($feature2)) { // This should be used for future changes
269
                $tmpreadok = 1;
270
                foreach ($feature2 as $subfeature) {
271
                    if (!empty($subfeature) && empty($user->rights->$feature->$subfeature->lire) && empty($user->rights->$feature->$subfeature->read)) {
272
                        $tmpreadok = 0;
273
                    } else if (empty($subfeature) && empty($user->rights->$feature->lire) && empty($user->rights->$feature->read)) {
274
                        $tmpreadok = 0;
275
                    } else {
276
                        $tmpreadok = 1;
277
                        break;
278
                    } // Break is to bypass second test if the first is ok
279
                }
280
                if (!$tmpreadok) { // We found a test on feature that is ko
281
                    $readok = 0; // All tests are ko (we manage here the and, the or will be managed later using $nbko).
282
                    $nbko++;
283
                }
284
            } else if (!empty($feature) && ($feature != 'user' && $feature != 'usergroup')) {  // This is for old permissions
285
                if (empty($user->rights->$feature->lire) && empty($user->rights->$feature->read) && empty($user->rights->$feature->run)) {
286
                    $readok = 0;
287
                    $nbko++;
288
                }
289
            }
290
        }
291
292
        // If a or and at least one ok
293
        if (preg_match('/\|/', $features) && $nbko < count($featuresarray))
294
            $readok = 1;
295
296
        if (!$readok)
297
            accessforbidden();
298
        //print "Read access is ok";
299
        // Check write permission from module (we need to know write permission to create but also to delete drafts record)
300
        $createok = 1;
301
        $nbko = 0;
302
        if (GETPOST('action', 'aZ09') == 'create' || ((GETPOST("action", "aZ09") == 'confirm_delete' && GETPOST("confirm", "aZ09") == 'yes') || GETPOST("action", "aZ09") == 'delete')) {
303
            foreach ($featuresarray as $feature) {
304
                if ($feature == 'contact') {
305
                    if (!$user->rights->societe->contact->creer) {
306
                        $createok = 0;
307
                        $nbko++;
308
                    }
309
                } else if ($feature == 'produit|service') {
310
                    if (!$user->rights->produit->creer && !$user->rights->service->creer) {
311
                        $createok = 0;
312
                        $nbko++;
313
                    }
314
                } else if ($feature == 'prelevement') {
315
                    if (!$user->rights->prelevement->bons->creer) {
316
                        $createok = 0;
317
                        $nbko++;
318
                    }
319
                } else if ($feature == 'commande_fournisseur') {
320
                    if (!$user->rights->fournisseur->commande->creer) {
321
                        $createok = 0;
322
                        $nbko++;
323
                    }
324
                } else if ($feature == 'banque') {
325
                    if (!$user->rights->banque->modifier) {
326
                        $createok = 0;
327
                        $nbko++;
328
                    }
329
                } else if ($feature == 'cheque') {
330
                    if (!$user->rights->banque->cheque) {
331
                        $createok = 0;
332
                        $nbko++;
333
                    }
334
                } else if (!empty($feature2)) { // This should be used
335
                    foreach ($feature2 as $subfeature) {
336
                        if (empty($user->rights->$feature->$subfeature->creer) && empty($user->rights->$feature->$subfeature->write) && empty($user->rights->$feature->$subfeature->create)) {
337
                            $createok = 0;
338
                            $nbko++;
339
                        } else {
340
                            $createok = 1;
341
                            break;
342
                        } // Break to bypass second test if the first is ok
343
                    }
344
                } else if (!empty($feature)) {  // This is for old permissions ('creer' or 'write')
345
                    //print '<br>feature='.$feature.' creer='.$user->rights->$feature->creer.' write='.$user->rights->$feature->write;
346
                    if (empty($user->rights->$feature->creer) && empty($user->rights->$feature->write) && empty($user->rights->$feature->create)) {
347
                        $createok = 0;
348
                        $nbko++;
349
                    }
350
                }
351
            }
352
353
            // If a or and at least one ok
354
            if (preg_match('/\|/', $features) && $nbko < count($featuresarray))
355
                $createok = 1;
356
357
            if (GETPOST('action', 'aZ09') == 'create' && !$createok)
358
                accessforbidden();
359
            //print "Write access is ok";
360
        }
361
362
        // Check create user permission
363
        $createuserok = 1;
364
        if (GETPOST('action', 'aZ09') == 'confirm_create_user' && GETPOST("confirm", 'aZ09') == 'yes') {
365
            if (!$user->rights->user->user->creer)
366
                $createuserok = 0;
367
368
            if (!$createuserok)
369
                accessforbidden();
370
            //print "Create user access is ok";
371
        }
372
373
        // Check delete permission from module
374
        $deleteok = 1;
375
        $nbko = 0;
376
        if ((GETPOST("action", "aZ09") == 'confirm_delete' && GETPOST("confirm", "aZ09") == 'yes') || GETPOST("action", "aZ09") == 'delete') {
377
            foreach ($featuresarray as $feature) {
378
                if ($feature == 'contact') {
379
                    if (!$user->rights->societe->contact->supprimer)
380
                        $deleteok = 0;
381
                }
382
                else if ($feature == 'produit|service') {
383
                    if (!$user->rights->produit->supprimer && !$user->rights->service->supprimer)
384
                        $deleteok = 0;
385
                }
386
                else if ($feature == 'commande_fournisseur') {
387
                    if (!$user->rights->fournisseur->commande->supprimer)
388
                        $deleteok = 0;
389
                }
390
                else if ($feature == 'banque') {
391
                    if (!$user->rights->banque->modifier)
392
                        $deleteok = 0;
393
                }
394
                else if ($feature == 'cheque') {
395
                    if (!$user->rights->banque->cheque)
396
                        $deleteok = 0;
397
                }
398
                else if ($feature == 'ecm') {
399
                    if (!$user->rights->ecm->upload)
400
                        $deleteok = 0;
401
                }
402
                else if ($feature == 'ftp') {
403
                    if (!$user->rights->ftp->write)
404
                        $deleteok = 0;
405
                }else if ($feature == 'salaries') {
406
                    if (!$user->rights->salaries->delete)
407
                        $deleteok = 0;
408
                }
409
                else if ($feature == 'salaries') {
410
                    if (!$user->rights->salaries->delete)
411
                        $deleteok = 0;
412
                }
413
                else if (!empty($feature2)) { // This should be used for permissions on 2 levels
414
                    foreach ($feature2 as $subfeature) {
415
                        if (empty($user->rights->$feature->$subfeature->supprimer) && empty($user->rights->$feature->$subfeature->delete))
416
                            $deleteok = 0;
417
                        else {
418
                            $deleteok = 1;
419
                            break;
420
                        } // For bypass the second test if the first is ok
421
                    }
422
                } else if (!empty($feature)) {  // This is used for permissions on 1 level
423
                    //print '<br>feature='.$feature.' creer='.$user->rights->$feature->supprimer.' write='.$user->rights->$feature->delete;
424
                    if (empty($user->rights->$feature->supprimer) && empty($user->rights->$feature->delete) && empty($user->rights->$feature->run))
425
                        $deleteok = 0;
426
                }
427
            }
428
429
            // If a or and at least one ok
430
            if (preg_match('/\|/', $features) && $nbko < count($featuresarray))
431
                $deleteok = 1;
432
433
            if (!$deleteok && !($isdraft && $createok))
434
                accessforbidden();
435
            //print "Delete access is ok";
436
        }
437
438
        // If we have a particular object to check permissions on, we check this object
439
        // is linked to a company allowed to $user.
440
        if (!empty($objectid) && $objectid > 0) {
441
            $ok = checkUserAccessToObject($user, $featuresarray, $objectid, $tableandshare, $feature2, $dbt_keyfield, $dbt_select);
442
            return $ok ? 1 : accessforbidden();
0 ignored issues
show
Bug introduced by
Are you sure the usage of accessforbidden() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
443
        }
444
445
        return 1;
446
    }
447
448
    /**
449
     * Check access by user to object.
450
     * This function is also called by restrictedArea
451
     *
452
     * @param User			$user			User to check
453
     * @param array			$featuresarray	Features/modules to check. Example: ('user','service','member','project','task',...)
454
     * @param int|string	$objectid		Object ID if we want to check a particular record (optional) is linked to a owned thirdparty (optional).
455
     * @param string		$tableandshare	'TableName&SharedElement' with Tablename is table where object is stored. SharedElement is an optional key to define where to check entity for multicompany modume. Param not used if objectid is null (optional).
456
     * @param string		$feature2		Feature to check, second level of permission (optional). Can be or check with 'level1|level2'.
457
     * @param string		$dbt_keyfield	Field name for socid foreign key if not fk_soc. Not used if objectid is null (optional)
458
     * @param string		$dbt_select		Field name for select if not rowid. Not used if objectid is null (optional)
459
     * @return	bool						True if user has access, False otherwise
460
     * @see restrictedArea
461
     */
462
    function checkUserAccessToObject($user, $featuresarray, $objectid = 0, $tableandshare = '', $feature2 = '', $dbt_keyfield = '', $dbt_select = 'rowid')
463
    {
464
        global $db, $conf;
465
466
        // More parameters
467
        $params = explode('&', $tableandshare);
468
        $dbtablename = (!empty($params[0]) ? $params[0] : '');
469
        $sharedelement = (!empty($params[1]) ? $params[1] : $dbtablename);
470
471
        foreach ($featuresarray as $feature) {
472
            $sql = '';
473
474
            // For backward compatibility
475
            if ($feature == 'member')
476
                $feature = 'adherent';
477
            if ($feature == 'project')
478
                $feature = 'projet';
479
            if ($feature == 'task')
480
                $feature = 'projet_task';
481
482
            $check = array('adherent', 'banque', 'don', 'user', 'usergroup', 'product', 'produit', 'service', 'produit|service', 'categorie', 'resource'); // Test on entity only (Objects with no link to company)
483
            $checksoc = array('societe');  // Test for societe object
484
            $checkother = array('contact', 'agenda');  // Test on entity and link to third party. Allowed if link is empty (Ex: contacts...).
485
            $checkproject = array('projet', 'project'); // Test for project object
486
            $checktask = array('projet_task');
487
            $nocheck = array('barcode', 'stock'); // No test
488
            $checkdefault = 'all other not already defined'; // Test on entity and link to third party. Not allowed if link is empty (Ex: invoice, orders...).
489
            // If dbtablename not defined, we use same name for table than module name
490
            if (empty($dbtablename)) {
491
                $dbtablename = $feature;
492
                $sharedelement = (!empty($params[1]) ? $params[1] : $dbtablename);  // We change dbtablename, so we set sharedelement too.
493
            }
494
495
            // Check permission for object with entity
496
            if (in_array($feature, $check)) {
497
                $sql = "SELECT COUNT(dbt." . $dbt_select . ") as nb";
498
                $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
499
                if (($feature == 'user' || $feature == 'usergroup') && !empty($conf->multicompany->enabled)) {
500
                    if (!empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) {
501
                        if ($conf->entity == 1 && $user->admin && !$user->entity) {
502
                            $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
503
                            $sql .= " AND dbt.entity IS NOT NULL";
504
                        } else {
505
                            $sql .= "," . MAIN_DB_PREFIX . "usergroup_user as ug";
506
                            $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
507
                            $sql .= " AND (ug.fk_user = dbt.rowid";
508
                            $sql .= " AND ug.entity IN (" . getEntity('user') . "))";
509
                            $sql .= " OR dbt.entity = 0"; // Show always superadmin
510
                        }
511
                    } else {
512
                        $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
513
                        $sql .= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
514
                    }
515
                } else {
516
                    $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
517
                    $sql .= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
518
                }
519
            } else if (in_array($feature, $checksoc)) { // We check feature = checksoc
520
                // If external user: Check permission for external users
521
                if ($user->socid > 0) {
522
                    if ($user->socid <> $objectid)
523
                        return false;
524
                }
525
                // If internal user: Check permission for internal users that are restricted on their objects
526
                else if (!empty($conf->societe->enabled) && ($user->rights->societe->lire && !$user->rights->societe->client->voir)) {
527
                    $sql = "SELECT COUNT(sc.fk_soc) as nb";
528
                    $sql .= " FROM (" . MAIN_DB_PREFIX . "societe_commerciaux as sc";
529
                    $sql .= ", " . MAIN_DB_PREFIX . "societe as s)";
530
                    $sql .= " WHERE sc.fk_soc IN (" . $objectid . ")";
531
                    $sql .= " AND sc.fk_user = " . $user->id;
532
                    $sql .= " AND sc.fk_soc = s.rowid";
533
                    $sql .= " AND s.entity IN (" . getEntity($sharedelement, 1) . ")";
534
                }
535
                // If multicompany and internal users with all permissions, check user is in correct entity
536
                else if (!empty($conf->multicompany->enabled)) {
537
                    $sql = "SELECT COUNT(s.rowid) as nb";
538
                    $sql .= " FROM " . MAIN_DB_PREFIX . "societe as s";
539
                    $sql .= " WHERE s.rowid IN (" . $objectid . ")";
540
                    $sql .= " AND s.entity IN (" . getEntity($sharedelement, 1) . ")";
541
                }
542
            } else if (in_array($feature, $checkother)) { // Test on entity and link to societe. Allowed if link is empty (Ex: contacts...).
543
                // If external user: Check permission for external users
544
                if ($user->socid > 0) {
545
                    $sql = "SELECT COUNT(dbt." . $dbt_select . ") as nb";
546
                    $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
547
                    $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
548
                    $sql .= " AND dbt.fk_soc = " . $user->socid;
549
                }
550
                // If internal user: Check permission for internal users that are restricted on their objects
551
                else if (!empty($conf->societe->enabled) && ($user->rights->societe->lire && !$user->rights->societe->client->voir)) {
552
                    $sql = "SELECT COUNT(dbt." . $dbt_select . ") as nb";
553
                    $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
554
                    $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "societe_commerciaux as sc ON dbt.fk_soc = sc.fk_soc AND sc.fk_user = '" . $user->id . "'";
555
                    $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
556
                    $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
557
                    $sql .= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
558
                }
559
                // If multicompany and internal users with all permissions, check user is in correct entity
560
                else if (!empty($conf->multicompany->enabled)) {
561
                    $sql = "SELECT COUNT(dbt." . $dbt_select . ") as nb";
562
                    $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
563
                    $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
564
                    $sql .= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
565
                }
566
            } else if (in_array($feature, $checkproject)) {
567
                if (!empty($conf->projet->enabled) && empty($user->rights->projet->all->lire)) {
568
                    include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
569
                    $projectstatic = new Project($db);
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\Project was not found. Did you mean Project? If so, make sure to prefix the type with \.
Loading history...
570
                    $tmps = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, 0);
571
                    $tmparray = explode(',', $tmps);
572
                    if (!in_array($objectid, $tmparray))
573
                        return false;
574
                }
575
                else {
576
                    $sql = "SELECT COUNT(dbt." . $dbt_select . ") as nb";
577
                    $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
578
                    $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
579
                    $sql .= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
580
                }
581
            } else if (in_array($feature, $checktask)) {
582
                if (!empty($conf->projet->enabled) && empty($user->rights->projet->all->lire)) {
583
                    $task = new Task($db);
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\Task was not found. Did you mean Task? If so, make sure to prefix the type with \.
Loading history...
584
                    $task->fetch($objectid);
585
586
                    include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php';
587
                    $projectstatic = new Project($db);
588
                    $tmps = $projectstatic->getProjectsAuthorizedForUser($user, 0, 1, 0);
589
                    $tmparray = explode(',', $tmps);
590
                    if (!in_array($task->fk_project, $tmparray))
591
                        return false;
592
                }
593
                else {
594
                    $sql = "SELECT COUNT(dbt." . $dbt_select . ") as nb";
595
                    $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
596
                    $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
597
                    $sql .= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
598
                }
599
            } else if (!in_array($feature, $nocheck)) {  // By default (case of $checkdefault), we check on object entity + link to third party on field $dbt_keyfield
600
                // If external user: Check permission for external users
601
                if ($user->socid > 0) {
602
                    if (empty($dbt_keyfield))
603
                        dol_print_error('', 'Param dbt_keyfield is required but not defined');
604
                    $sql = "SELECT COUNT(dbt." . $dbt_keyfield . ") as nb";
605
                    $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
606
                    $sql .= " WHERE dbt.rowid IN (" . $objectid . ")";
607
                    $sql .= " AND dbt." . $dbt_keyfield . " = " . $user->socid;
608
                }
609
                // If internal user: Check permission for internal users that are restricted on their objects
610
                else if (!empty($conf->societe->enabled) && ($user->rights->societe->lire && !$user->rights->societe->client->voir)) {
611
                    if (empty($dbt_keyfield))
612
                        dol_print_error('', 'Param dbt_keyfield is required but not defined');
613
                    $sql = "SELECT COUNT(sc.fk_soc) as nb";
614
                    $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
615
                    $sql .= ", " . MAIN_DB_PREFIX . "societe as s";
616
                    $sql .= ", " . MAIN_DB_PREFIX . "societe_commerciaux as sc";
617
                    $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
618
                    $sql .= " AND sc.fk_soc = dbt." . $dbt_keyfield;
619
                    $sql .= " AND dbt." . $dbt_keyfield . " = s.rowid";
620
                    $sql .= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
621
                    $sql .= " AND sc.fk_user = " . $user->id;
622
                }
623
                // If multicompany and internal users with all permissions, check user is in correct entity
624
                else if (!empty($conf->multicompany->enabled)) {
625
                    $sql = "SELECT COUNT(dbt." . $dbt_select . ") as nb";
626
                    $sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt";
627
                    $sql .= " WHERE dbt." . $dbt_select . " IN (" . $objectid . ")";
628
                    $sql .= " AND dbt.entity IN (" . getEntity($sharedelement, 1) . ")";
629
                }
630
            }
631
632
            if ($sql) {
633
                $resql = $db->query($sql);
634
                if ($resql) {
635
                    $obj = $db->fetch_object($resql);
636
                    if (!$obj || $obj->nb < count(explode(',', $objectid)))
637
                        return false;
638
                }
639
                else {
640
                    return false;
641
                }
642
            }
643
        }
644
        return true;
645
    }
646
647
    /**
648
     * 	Show a message to say access is forbidden and stop program
649
     * 	Calling this function terminate execution of PHP.
650
     *
651
     * 	@param	string	$message			    Force error message
652
     * 	@param	int		$printheader		    Show header before
653
     *  @param  int		$printfooter         Show footer after
654
     *  @param  int		$showonlymessage     Show only message parameter. Otherwise add more information.
655
     *  @return	void
656
     */
657
    function accessforbidden($message = '', $printheader = 1, $printfooter = 1, $showonlymessage = 0)
658
    {
659
        global $conf, $db, $user, $langs;
660
        if (!is_object($langs)) {
661
            include_once DOL_DOCUMENT_ROOT . '/core/class/translate.class.php';
662
            $langs = new Translate('', $conf);
0 ignored issues
show
Bug introduced by
The type Alixar\Helpers\Translate was not found. Did you mean Translate? If so, make sure to prefix the type with \.
Loading history...
663
            $langs->setDefaultLang();
664
        }
665
666
        $langs->load("errors");
667
668
        if ($printheader) {
669
            if (function_exists("llxHeader"))
670
                llxHeader('');
671
            else if (function_exists("llxHeaderVierge"))
672
                llxHeaderVierge('');
673
        }
674
        print '<div class="error">';
675
        if (!$message)
676
            print $langs->trans("ErrorForbidden");
677
        else
678
            print $message;
679
        print '</div>';
680
        print '<br>';
681
        if (empty($showonlymessage)) {
682
            if ($user->login) {
683
                print $langs->trans("CurrentLogin") . ': <font class="error">' . $user->login . '</font><br>';
684
                print $langs->trans("ErrorForbidden2", $langs->trans("Home"), $langs->trans("Users"));
685
            } else {
686
                print $langs->trans("ErrorForbidden3");
687
            }
688
        }
689
        if ($printfooter && function_exists("llxFooter"))
690
            llxFooter();
691
        exit(0);
0 ignored issues
show
Best Practice introduced by
Using exit here is not recommended.

In general, usage of exit should be done with care and only when running in a scripting context like a CLI script.

Loading history...
692
    }
693
}
694