2008-04-29 23:13:49 +02:00
< ? php
2011-03-30 09:55:22 +02:00
/* Copyright ( C ) 2008 - 2011 Laurent Destailleur < eldy @ users . sourceforge . net >
2017-03-13 15:00:44 +01:00
* Copyright ( C ) 2008 - 2017 Regis Houssin < regis . houssin @ capnetworks . com >
2008-04-29 23:13:49 +02:00
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
2013-01-16 15:36:08 +01:00
* the Free Software Foundation ; either version 3 of the License , or
2008-04-29 23:13:49 +02:00
* ( at your option ) any later version .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
2011-08-01 01:24:38 +02:00
* along with this program . If not , see < http :// www . gnu . org / licenses />.
2008-04-29 23:13:49 +02:00
* or see http :// www . gnu . org /
*/
/**
2011-10-24 10:45:06 +02:00
* \file htdocs / core / lib / security . lib . php
2011-09-24 15:44:04 +02:00
* \ingroup core
2012-02-12 17:41:28 +01:00
* \brief Set of function used for dolibarr security ( common function included into filefunc . inc . php )
2011-09-24 15:44:04 +02:00
* Warning , this file must not depends on other library files , except function . lib . php
* because it is used at low code level .
2008-11-17 01:02:57 +01:00
*/
2008-04-29 23:13:49 +02:00
/**
2018-04-19 12:03:42 +02:00
* Encode a string with base 64 algorithm + specific delta change .
2011-09-16 19:06:10 +02:00
*
2012-02-19 19:14:17 +01:00
* @ param string $chain string to encode
2018-04-19 12:03:42 +02:00
* @ param string $key rule to use for delta ( '0' , '1' or 'myownkey' )
2012-02-19 19:14:17 +01:00
* @ return string encoded string
2018-04-19 12:03:42 +02:00
* @ see dol_decode
2008-04-29 23:13:49 +02:00
*/
2018-04-19 12:03:42 +02:00
function dol_encode ( $chain , $key = '1' )
2008-04-29 23:13:49 +02:00
{
2018-04-19 12:03:42 +02:00
if ( is_numeric ( $key ) && $key == '1' ) // rule 1 is offset of 17 for char
2008-04-29 23:13:49 +02:00
{
2018-05-16 15:23:52 +02:00
$output_tab = array ();
2018-10-29 18:19:40 +01:00
$strlength = dol_strlen ( $chain );
2018-04-19 12:03:42 +02:00
for ( $i = 0 ; $i < $strlength ; $i ++ )
{
$output_tab [ $i ] = chr ( ord ( substr ( $chain , $i , 1 )) + 17 );
}
$chain = implode ( " " , $output_tab );
}
elseif ( $key )
{
$result = '' ;
$strlength = dol_strlen ( $chain );
for ( $i = 0 ; $i < $strlength ; $i ++ )
{
$keychar = substr ( $key , ( $i % strlen ( $key )) - 1 , 1 );
$result .= chr ( ord ( substr ( $chain , $i , 1 )) + ( ord ( $keychar ) - 65 ));
}
$chain = $result ;
2008-04-29 23:13:49 +02:00
}
2018-04-19 12:03:42 +02:00
return base64_encode ( $chain );
2008-04-29 23:13:49 +02:00
}
/**
2018-04-19 12:03:42 +02:00
* Decode a base 64 encoded + specific delta change .
2012-02-19 19:14:17 +01:00
* This function is called by filefunc . inc . php at each page call .
2011-09-16 19:06:10 +02:00
*
2012-02-19 19:14:17 +01:00
* @ param string $chain string to decode
2018-04-19 12:03:42 +02:00
* @ param string $key rule to use for delta ( '0' , '1' or 'myownkey' )
2012-02-19 19:14:17 +01:00
* @ return string decoded string
2018-04-19 12:03:42 +02:00
* @ see dol_encode
2008-04-29 23:13:49 +02:00
*/
2018-04-19 12:03:42 +02:00
function dol_decode ( $chain , $key = '1' )
2008-04-29 23:13:49 +02:00
{
$chain = base64_decode ( $chain );
2018-04-19 12:03:42 +02:00
if ( is_numeric ( $key ) && $key == '1' ) // rule 1 is offset of 17 for char
2008-04-29 23:13:49 +02:00
{
2018-05-16 15:23:52 +02:00
$output_tab = array ();
2018-04-19 12:03:42 +02:00
$strlength = dol_strlen ( $chain );
for ( $i = 0 ; $i < $strlength ; $i ++ )
{
$output_tab [ $i ] = chr ( ord ( substr ( $chain , $i , 1 )) - 17 );
}
$chain = implode ( " " , $output_tab );
}
elseif ( $key )
2008-04-29 23:13:49 +02:00
{
2018-04-19 12:03:42 +02:00
$result = '' ;
$strlength = dol_strlen ( $chain );
for ( $i = 0 ; $i < $strlength ; $i ++ )
{
$keychar = substr ( $key , ( $i % strlen ( $key )) - 1 , 1 );
$result .= chr ( ord ( substr ( $chain , $i , 1 )) - ( ord ( $keychar ) - 65 ));
}
$chain = $result ;
2008-04-29 23:13:49 +02:00
}
2018-04-19 12:03:42 +02:00
return $chain ;
2008-04-29 23:13:49 +02:00
}
2008-11-17 01:02:57 +01:00
2011-05-03 12:53:44 +02:00
/**
2013-11-06 16:32:25 +01:00
* Returns a hash of a string .
2018-02-23 14:38:41 +01:00
* If constant MAIN_SECURITY_HASH_ALGO is defined , we use this function as hashing function ( recommanded value is 'password_hash' )
* If constant MAIN_SECURITY_SALT is defined , we use it as a salt ( used only if hashing algorightm is something else than 'password_hash' ) .
2011-09-16 19:06:10 +02:00
*
* @ param string $chain String to hash
2018-05-01 20:31:57 +02:00
* @ 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' .
2011-09-16 19:06:10 +02:00
* @ return string Hash of string
2018-01-24 14:37:26 +01:00
* @ getRandomPassword
2011-05-03 12:53:44 +02:00
*/
2017-11-03 20:04:18 +01:00
function dol_hash ( $chain , $type = '0' )
2011-05-03 12:53:44 +02:00
{
2013-11-04 10:45:43 +01:00
global $conf ;
2013-11-06 16:32:25 +01:00
2018-01-15 00:33:25 +01:00
// No need to add salt for password_hash
2018-02-23 14:38:41 +01:00
if (( $type == '0' || $type == 'auto' ) && ! empty ( $conf -> global -> MAIN_SECURITY_HASH_ALGO ) && $conf -> global -> MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists ( 'password_hash' ))
{
return password_hash ( $chain , PASSWORD_DEFAULT );
}
2018-01-15 00:33:25 +01:00
2013-11-04 10:47:24 +01:00
// Salt value
if ( ! empty ( $conf -> global -> MAIN_SECURITY_SALT )) $chain = $conf -> global -> MAIN_SECURITY_SALT . $chain ;
2013-11-06 16:32:25 +01:00
2017-11-03 20:04:18 +01:00
if ( $type == '1' || $type == 'sha1' ) return sha1 ( $chain );
else if ( $type == '2' || $type == 'sha1md5' ) return sha1 ( md5 ( $chain ));
else if ( $type == '3' || $type == 'md5' ) return md5 ( $chain );
else if ( $type == '4' || $type == 'md5openldap' ) return '{md5}' . base64_encode ( mhash ( MHASH_MD5 , $chain )); // For OpenLdap with md5 (based on an unencrypted password in base)
2017-11-30 14:21:55 +01:00
else if ( $type == '5' ) return hash ( 'sha256' , $chain );
2013-11-06 16:32:25 +01:00
else if ( ! empty ( $conf -> global -> MAIN_SECURITY_HASH_ALGO ) && $conf -> global -> MAIN_SECURITY_HASH_ALGO == 'sha1' ) return sha1 ( $chain );
else if ( ! empty ( $conf -> global -> MAIN_SECURITY_HASH_ALGO ) && $conf -> global -> MAIN_SECURITY_HASH_ALGO == 'sha1md5' ) return sha1 ( md5 ( $chain ));
2014-10-18 16:08:15 +02:00
2017-11-03 20:04:18 +01:00
// No particular encoding defined, use default
2014-10-18 16:08:15 +02:00
return md5 ( $chain );
2011-05-03 12:53:44 +02:00
}
2018-01-15 00:33:25 +01:00
/**
* Compute a hash and compare it to the given one
* For backward compatibility reasons , if the hash is not in the password_hash format , we will try to match against md5 and sha1md5
* If constant MAIN_SECURITY_HASH_ALGO is defined , we use this function as hashing function .
* If constant MAIN_SECURITY_SALT is defined , we use it as a salt .
*
* @ param string $chain String to hash
* @ param string $hash hash to compare
* @ 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' .
* @ return bool True if the computed hash is the same as the given one
*/
function dol_verifyHash ( $chain , $hash , $type = '0' )
{
global $conf ;
2018-01-15 11:02:08 +01:00
if ( $type == '0' && ! empty ( $conf -> global -> MAIN_SECURITY_HASH_ALGO ) && $conf -> global -> MAIN_SECURITY_HASH_ALGO == 'password_hash' && function_exists ( 'password_verify' )) {
2018-01-15 00:33:25 +01:00
if ( $hash [ 0 ] == '$' ) return password_verify ( $chain , $hash );
else if ( strlen ( $hash ) == 32 ) return dol_verifyHash ( $chain , $hash , '3' ); // md5
else if ( strlen ( $hash ) == 40 ) return dol_verifyHash ( $chain , $hash , '2' ); // sha1md5
return false ;
}
return dol_hash ( $chain , $type ) == $hash ;
}
2012-02-12 17:41:28 +01:00
/**
* Check permissions of a user to show a page and an object . Check read permission .
2017-05-16 13:27:32 +02:00
* If GETPOST ( 'action' , 'aZ09' ) defined , we also check write and delete permission .
2012-02-12 17:41:28 +01:00
*
* @ param User $user User to check
2014-05-10 18:57:04 +02:00
* @ param string $features Features to check ( it must be module name . Examples : 'societe' , 'contact' , 'produit&service' , 'produit|service' , ... )
2014-03-05 09:57:36 +01:00
* @ param int $objectid Object ID if we want to check a particular record ( optional ) is linked to a owned thirdparty ( optional ) .
2017-03-02 11:46:31 +01:00
* @ 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 ) .
2018-02-12 02:53:08 +01:00
* @ param string $feature2 Feature to check , second level of permission ( optional ) . Can be a 'or' check with 'level1|level2' .
2014-03-05 09:57:36 +01:00
* @ param string $dbt_keyfield Field name for socid foreign key if not fk_soc . Not used if objectid is null ( optional )
* @ param string $dbt_select Field name for select if not rowid . Not used if objectid is null ( optional )
2012-02-12 17:41:28 +01:00
* @ param Canvas $objcanvas Object canvas
2018-10-29 18:19:40 +01:00
* @ param int $isdraft 1 = The object with id = $objectid is a draft
2012-02-12 17:41:28 +01:00
* @ return int Always 1 , die process if not allowed
2017-05-19 20:17:33 +02:00
* @ see dol_check_secure_access_document
2012-02-12 17:41:28 +01:00
*/
2018-10-29 18:19:40 +01:00
function restrictedArea ( $user , $features , $objectid = 0 , $tableandshare = '' , $feature2 = '' , $dbt_keyfield = 'fk_soc' , $dbt_select = 'rowid' , $objcanvas = null , $isdraft = 0 )
2012-02-12 17:41:28 +01:00
{
2018-05-10 11:30:27 +02:00
global $db , $conf ;
global $hookmanager ;
2012-02-12 17:41:28 +01:00
2018-10-29 18:19:40 +01:00
//dol_syslog("functions.lib:restrictedArea $feature, $objectid, $dbtablename,$feature2,$dbt_socfield,$dbt_select");
//print "user_id=".$user->id.", features=".$features.", feature2=".$feature2.", objectid=".$objectid;
//print ", dbtablename=".$dbtablename.", dbt_socfield=".$dbt_keyfield.", dbt_select=".$dbt_select;
//print ", perm: ".$features."->".$feature2."=".($user->rights->$features->$feature2->lire)."<br>";
2012-02-12 17:41:28 +01:00
2018-05-10 11:30:27 +02:00
// Get more permissions checks from hooks
$parameters = array ( 'features' => $features , 'objectid' => $objectid , 'idtype' => $dbt_select );
$reshook = $hookmanager -> executeHooks ( 'restrictedArea' , $parameters );
2018-05-10 12:29:58 +02:00
if ( ! empty ( $hookmanager -> resArray [ 'result' ])) return true ;
2018-05-10 11:34:20 +02:00
if ( $reshook > 0 ) return false ;
2018-05-10 12:29:58 +02:00
2018-05-10 12:34:23 +02:00
if ( $dbt_select != 'rowid' && $dbt_select != 'id' ) $objectid = " ' " . $objectid . " ' " ;
// Features/modules to check
2018-10-29 18:19:40 +01:00
$featuresarray = array ( $features );
if ( preg_match ( '/&/' , $features )) $featuresarray = explode ( " & " , $features );
else if ( preg_match ( '/\|/' , $features )) $featuresarray = explode ( " | " , $features );
2012-02-12 17:41:28 +01:00
2018-10-29 18:19:40 +01:00
// More subfeatures to check
if ( ! empty ( $feature2 )) $feature2 = explode ( " | " , $feature2 );
2013-04-26 16:07:35 +02:00
2018-10-29 18:19:40 +01:00
// More parameters
$params = explode ( '&' , $tableandshare );
$dbtablename = ( ! empty ( $params [ 0 ]) ? $params [ 0 ] : '' );
$sharedelement = ( ! empty ( $params [ 1 ]) ? $params [ 1 ] : $dbtablename );
2012-02-12 17:41:28 +01:00
2013-01-02 18:43:59 +01:00
$listofmodules = explode ( ',' , $conf -> global -> MAIN_MODULES_FOR_EXTERNAL );
// Check read permission from module
2018-10-29 18:19:40 +01:00
$readok = 1 ; $nbko = 0 ;
foreach ( $featuresarray as $feature ) // first we check nb of test ko
{
$featureforlistofmodule = $feature ;
if ( $featureforlistofmodule == 'produit' ) $featureforlistofmodule = 'product' ;
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
{
$readok = 0 ; $nbko ++ ;
continue ;
}
if ( $feature == 'societe' )
{
if ( ! $user -> rights -> societe -> lire && ! $user -> rights -> fournisseur -> lire ) { $readok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'contact' )
{
if ( ! $user -> rights -> societe -> contact -> lire ) { $readok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'produit|service' )
{
if ( ! $user -> rights -> produit -> lire && ! $user -> rights -> service -> lire ) { $readok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'prelevement' )
{
if ( ! $user -> rights -> prelevement -> bons -> lire ) { $readok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'cheque' )
{
if ( ! $user -> rights -> banque -> cheque ) { $readok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'projet' )
{
if ( ! $user -> rights -> projet -> lire && ! $user -> rights -> projet -> all -> lire ) { $readok = 0 ; $nbko ++ ; }
}
else if ( ! empty ( $feature2 )) // This should be used for future changes
{
$tmpreadok = 1 ;
foreach ( $feature2 as $subfeature )
{
if ( ! empty ( $subfeature ) && empty ( $user -> rights -> $feature -> $subfeature -> lire ) && empty ( $user -> rights -> $feature -> $subfeature -> read )) { $tmpreadok = 0 ; }
else if ( empty ( $subfeature ) && empty ( $user -> rights -> $feature -> lire ) && empty ( $user -> rights -> $feature -> read )) { $tmpreadok = 0 ; }
else { $tmpreadok = 1 ; break ; } // Break is to bypass second test if the first is ok
}
if ( ! $tmpreadok ) // We found a test on feature that is ko
{
$readok = 0 ; // All tests are ko (we manage here the and, the or will be managed later using $nbko).
$nbko ++ ;
}
}
else if ( ! empty ( $feature ) && ( $feature != 'user' && $feature != 'usergroup' )) // This is for old permissions
{
if ( empty ( $user -> rights -> $feature -> lire )
&& empty ( $user -> rights -> $feature -> read )
&& empty ( $user -> rights -> $feature -> run )) { $readok = 0 ; $nbko ++ ; }
}
}
// If a or and at least one ok
if ( preg_match ( '/\|/' , $features ) && $nbko < count ( $featuresarray )) $readok = 1 ;
if ( ! $readok ) accessforbidden ();
//print "Read access is ok";
// Check write permission from module (we need to know write permission to create but also to delete drafts record)
$createok = 1 ; $nbko = 0 ;
if ( GETPOST ( 'action' , 'aZ09' ) == 'create' || (( GETPOST ( " action " , " aZ09 " ) == 'confirm_delete' && GETPOST ( " confirm " , " aZ09 " ) == 'yes' ) || GETPOST ( " action " , " aZ09 " ) == 'delete' ))
{
foreach ( $featuresarray as $feature )
{
if ( $feature == 'contact' )
{
if ( ! $user -> rights -> societe -> contact -> creer ) { $createok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'produit|service' )
{
if ( ! $user -> rights -> produit -> creer && ! $user -> rights -> service -> creer ) { $createok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'prelevement' )
{
if ( ! $user -> rights -> prelevement -> bons -> creer ) { $createok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'commande_fournisseur' )
{
if ( ! $user -> rights -> fournisseur -> commande -> creer ) { $createok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'banque' )
{
if ( ! $user -> rights -> banque -> modifier ) { $createok = 0 ; $nbko ++ ; }
}
else if ( $feature == 'cheque' )
{
if ( ! $user -> rights -> banque -> cheque ) { $createok = 0 ; $nbko ++ ; }
}
else if ( ! empty ( $feature2 )) // This should be used
{
foreach ( $feature2 as $subfeature )
{
if ( empty ( $user -> rights -> $feature -> $subfeature -> creer )
&& empty ( $user -> rights -> $feature -> $subfeature -> write )
&& empty ( $user -> rights -> $feature -> $subfeature -> create )) { $createok = 0 ; $nbko ++ ; }
else { $createok = 1 ; break ; } // Break to bypass second test if the first is ok
}
}
else if ( ! empty ( $feature )) // This is for old permissions ('creer' or 'write')
{
//print '<br>feature='.$feature.' creer='.$user->rights->$feature->creer.' write='.$user->rights->$feature->write;
if ( empty ( $user -> rights -> $feature -> creer )
&& empty ( $user -> rights -> $feature -> write )
&& empty ( $user -> rights -> $feature -> create )) { $createok = 0 ; $nbko ++ ; }
}
}
// If a or and at least one ok
if ( preg_match ( '/\|/' , $features ) && $nbko < count ( $featuresarray )) $createok = 1 ;
if ( GETPOST ( 'action' , 'aZ09' ) == 'create' && ! $createok ) accessforbidden ();
//print "Write access is ok";
}
// Check create user permission
$createuserok = 1 ;
if ( GETPOST ( 'action' , 'aZ09' ) == 'confirm_create_user' && GETPOST ( " confirm " , 'aZ09' ) == 'yes' )
{
if ( ! $user -> rights -> user -> user -> creer ) $createuserok = 0 ;
if ( ! $createuserok ) accessforbidden ();
//print "Create user access is ok";
}
// Check delete permission from module
$deleteok = 1 ; $nbko = 0 ;
if (( GETPOST ( " action " , " aZ09 " ) == 'confirm_delete' && GETPOST ( " confirm " , " aZ09 " ) == 'yes' ) || GETPOST ( " action " , " aZ09 " ) == 'delete' )
{
foreach ( $featuresarray as $feature )
{
if ( $feature == 'contact' )
{
if ( ! $user -> rights -> societe -> contact -> supprimer ) $deleteok = 0 ;
}
else if ( $feature == 'produit|service' )
{
if ( ! $user -> rights -> produit -> supprimer && ! $user -> rights -> service -> supprimer ) $deleteok = 0 ;
}
else if ( $feature == 'commande_fournisseur' )
{
if ( ! $user -> rights -> fournisseur -> commande -> supprimer ) $deleteok = 0 ;
}
else if ( $feature == 'banque' )
{
if ( ! $user -> rights -> banque -> modifier ) $deleteok = 0 ;
}
else if ( $feature == 'cheque' )
{
if ( ! $user -> rights -> banque -> cheque ) $deleteok = 0 ;
}
else if ( $feature == 'ecm' )
{
if ( ! $user -> rights -> ecm -> upload ) $deleteok = 0 ;
}
else if ( $feature == 'ftp' )
{
if ( ! $user -> rights -> ftp -> write ) $deleteok = 0 ;
} else if ( $feature == 'salaries' )
{
if ( ! $user -> rights -> salaries -> delete ) $deleteok = 0 ;
}
else if ( $feature == 'salaries' )
{
if ( ! $user -> rights -> salaries -> delete ) $deleteok = 0 ;
}
else if ( ! empty ( $feature2 )) // This should be used for permissions on 2 levels
{
foreach ( $feature2 as $subfeature )
{
if ( empty ( $user -> rights -> $feature -> $subfeature -> supprimer ) && empty ( $user -> rights -> $feature -> $subfeature -> delete )) $deleteok = 0 ;
else { $deleteok = 1 ; break ; } // For bypass the second test if the first is ok
}
}
else if ( ! empty ( $feature )) // This is used for permissions on 1 level
{
//print '<br>feature='.$feature.' creer='.$user->rights->$feature->supprimer.' write='.$user->rights->$feature->delete;
if ( empty ( $user -> rights -> $feature -> supprimer )
&& empty ( $user -> rights -> $feature -> delete )
&& empty ( $user -> rights -> $feature -> run )) $deleteok = 0 ;
}
}
// If a or and at least one ok
if ( preg_match ( '/\|/' , $features ) && $nbko < count ( $featuresarray )) $deleteok = 1 ;
if ( ! $deleteok && ! ( $isdraft && $createok )) accessforbidden ();
//print "Delete access is ok";
}
// If we have a particular object to check permissions on, we check this object
// is linked to a company allowed to $user.
if ( ! empty ( $objectid ) && $objectid > 0 )
{
$ok = checkUserAccessToObject ( $user , $featuresarray , $objectid , $tableandshare , $feature2 , $dbt_keyfield , $dbt_select );
return $ok ? 1 : accessforbidden ();
}
return 1 ;
2012-02-12 17:41:28 +01:00
}
2015-05-03 14:41:51 +02:00
/**
2017-01-29 16:42:59 +01:00
* Check access by user to object .
* This function is also called by restrictedArea
2015-05-31 03:30:38 +02:00
*
2017-12-18 15:39:40 +01:00
* @ param User $user User to check
* @ param array $featuresarray Features / modules to check . Example : ( 'user' , 'service' , 'member' , 'project' , 'task' , ... )
* @ param int | string $objectid Object ID if we want to check a particular record ( optional ) is linked to a owned thirdparty ( optional ) .
* @ 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 ) .
* @ param string $feature2 Feature to check , second level of permission ( optional ) . Can be or check with 'level1|level2' .
* @ param string $dbt_keyfield Field name for socid foreign key if not fk_soc . Not used if objectid is null ( optional )
* @ param string $dbt_select Field name for select if not rowid . Not used if objectid is null ( optional )
* @ return bool True if user has access , False otherwise
2017-01-29 16:42:59 +01:00
* @ see restrictedArea
2015-05-03 14:41:51 +02:00
*/
2015-07-16 10:59:00 +02:00
function checkUserAccessToObject ( $user , $featuresarray , $objectid = 0 , $tableandshare = '' , $feature2 = '' , $dbt_keyfield = '' , $dbt_select = 'rowid' )
2015-05-03 14:41:51 +02:00
{
global $db , $conf ;
2015-05-31 03:30:38 +02:00
2015-05-03 14:41:51 +02:00
// More parameters
2015-05-13 09:32:54 +02:00
$params = explode ( '&' , $tableandshare );
2015-05-03 14:41:51 +02:00
$dbtablename = ( ! empty ( $params [ 0 ]) ? $params [ 0 ] : '' );
$sharedelement = ( ! empty ( $params [ 1 ]) ? $params [ 1 ] : $dbtablename );
2015-05-31 03:30:38 +02:00
2015-05-03 14:41:51 +02:00
foreach ( $featuresarray as $feature )
{
$sql = '' ;
2017-02-03 11:42:49 +01:00
// For backward compatibility
2017-12-18 15:39:40 +01:00
if ( $feature == 'member' ) $feature = 'adherent' ;
2017-06-01 19:53:12 +02:00
if ( $feature == 'project' ) $feature = 'projet' ;
2017-12-18 15:39:40 +01:00
if ( $feature == 'task' ) $feature = 'projet_task' ;
2017-03-13 15:00:44 +01:00
2018-04-27 20:54:48 +02:00
$check = array ( 'adherent' , 'banque' , 'don' , 'user' , 'usergroup' , 'product' , 'produit' , 'service' , 'produit|service' , 'categorie' , 'resource' ); // Test on entity only (Objects with no link to company)
2015-05-03 14:41:51 +02:00
$checksoc = array ( 'societe' ); // Test for societe object
2017-08-24 08:33:40 +02:00
$checkother = array ( 'contact' , 'agenda' ); // Test on entity and link to third party. Allowed if link is empty (Ex: contacts...).
2017-06-01 17:29:47 +02:00
$checkproject = array ( 'projet' , 'project' ); // Test for project object
2017-06-01 19:53:12 +02:00
$checktask = array ( 'projet_task' );
2018-01-16 19:52:14 +01:00
$nocheck = array ( 'barcode' , 'stock' ); // No test
2015-05-03 14:41:51 +02:00
$checkdefault = 'all other not already defined' ; // Test on entity and link to third party. Not allowed if link is empty (Ex: invoice, orders...).
2017-10-17 12:58:26 +02:00
// If dbtablename not defined, we use same name for table than module name
if ( empty ( $dbtablename ))
{
$dbtablename = $feature ;
$sharedelement = ( ! empty ( $params [ 1 ]) ? $params [ 1 ] : $dbtablename ); // We change dbtablename, so we set sharedelement too.
}
2015-05-03 14:41:51 +02:00
// Check permission for object with entity
if ( in_array ( $feature , $check ))
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(dbt. " . $dbt_select . " ) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
2018-07-02 10:09:56 +02:00
if (( $feature == 'user' || $feature == 'usergroup' ) && ! empty ( $conf -> multicompany -> enabled ))
2015-05-03 14:41:51 +02:00
{
2018-07-02 10:09:56 +02:00
if ( ! empty ( $conf -> global -> MULTICOMPANY_TRANSVERSE_MODE ))
{
if ( $conf -> entity == 1 && $user -> admin && ! $user -> entity )
{
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
$sql .= " AND dbt.entity IS NOT NULL " ;
}
else
{
$sql .= " , " . MAIN_DB_PREFIX . " usergroup_user as ug " ;
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
$sql .= " AND (ug.fk_user = dbt.rowid " ;
$sql .= " AND ug.entity IN ( " . getEntity ( 'user' ) . " )) " ;
$sql .= " OR dbt.entity = 0 " ; // Show always superadmin
}
}
else {
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
$sql .= " AND dbt.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
2015-05-03 14:41:51 +02:00
}
else
{
2018-07-02 10:09:56 +02:00
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND dbt.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
}
else if ( in_array ( $feature , $checksoc )) // We check feature = checksoc
{
// If external user: Check permission for external users
2017-06-15 21:51:31 +02:00
if ( $user -> socid > 0 )
2015-05-03 14:41:51 +02:00
{
2017-06-15 21:51:31 +02:00
if ( $user -> socid <> $objectid ) return false ;
2015-05-03 14:41:51 +02:00
}
// If internal user: Check permission for internal users that are restricted on their objects
else if ( ! empty ( $conf -> societe -> enabled ) && ( $user -> rights -> societe -> lire && ! $user -> rights -> societe -> client -> voir ))
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(sc.fk_soc) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM ( " . MAIN_DB_PREFIX . " societe_commerciaux as sc " ;
$sql .= " , " . MAIN_DB_PREFIX . " societe as s) " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE sc.fk_soc IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND sc.fk_user = " . $user -> id ;
$sql .= " AND sc.fk_soc = s.rowid " ;
$sql .= " AND s.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
// If multicompany and internal users with all permissions, check user is in correct entity
else if ( ! empty ( $conf -> multicompany -> enabled ))
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(s.rowid) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . " societe as s " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE s.rowid IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND s.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
}
2015-07-16 10:59:00 +02:00
else if ( in_array ( $feature , $checkother )) // Test on entity and link to societe. Allowed if link is empty (Ex: contacts...).
2015-05-03 14:41:51 +02:00
{
// If external user: Check permission for external users
2018-07-02 10:09:56 +02:00
if ( $user -> socid > 0 )
2015-05-03 14:41:51 +02:00
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(dbt. " . $dbt_select . " ) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
2018-07-02 10:09:56 +02:00
$sql .= " AND dbt.fk_soc = " . $user -> socid ;
2015-05-03 14:41:51 +02:00
}
// If internal user: Check permission for internal users that are restricted on their objects
else if ( ! empty ( $conf -> societe -> enabled ) && ( $user -> rights -> societe -> lire && ! $user -> rights -> societe -> client -> voir ))
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(dbt. " . $dbt_select . " ) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
$sql .= " LEFT JOIN " . MAIN_DB_PREFIX . " societe_commerciaux as sc ON dbt.fk_soc = sc.fk_soc AND sc.fk_user = ' " . $user -> id . " ' " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$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
$sql .= " AND dbt.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
// If multicompany and internal users with all permissions, check user is in correct entity
else if ( ! empty ( $conf -> multicompany -> enabled ))
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(dbt. " . $dbt_select . " ) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND dbt.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
}
else if ( in_array ( $feature , $checkproject ))
{
2017-06-01 19:53:12 +02:00
if ( ! empty ( $conf -> projet -> enabled ) && empty ( $user -> rights -> projet -> all -> lire ))
2015-05-03 14:41:51 +02:00
{
include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php' ;
$projectstatic = new Project ( $db );
$tmps = $projectstatic -> getProjectsAuthorizedForUser ( $user , 0 , 1 , 0 );
$tmparray = explode ( ',' , $tmps );
if ( ! in_array ( $objectid , $tmparray )) return false ;
}
else
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(dbt. " . $dbt_select . " ) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND dbt.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
}
2017-06-01 19:53:12 +02:00
else if ( in_array ( $feature , $checktask ))
{
if ( ! empty ( $conf -> projet -> enabled ) && empty ( $user -> rights -> projet -> all -> lire ))
{
2018-10-29 18:19:40 +01:00
$task = new Task ( $db );
$task -> fetch ( $objectid );
2017-06-01 19:53:12 +02:00
include_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php' ;
$projectstatic = new Project ( $db );
$tmps = $projectstatic -> getProjectsAuthorizedForUser ( $user , 0 , 1 , 0 );
$tmparray = explode ( ',' , $tmps );
if ( ! in_array ( $task -> fk_project , $tmparray )) return false ;
}
else
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(dbt. " . $dbt_select . " ) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND dbt.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
}
2018-01-16 19:52:14 +01:00
else if ( ! in_array ( $feature , $nocheck )) // By default (case of $checkdefault), we check on object entity + link to third party on field $dbt_keyfield
2015-05-03 14:41:51 +02:00
{
// If external user: Check permission for external users
2018-07-02 10:09:56 +02:00
if ( $user -> socid > 0 )
2015-05-03 14:41:51 +02:00
{
if ( empty ( $dbt_keyfield )) dol_print_error ( '' , 'Param dbt_keyfield is required but not defined' );
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(dbt. " . $dbt_keyfield . " ) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE dbt.rowid IN ( " . $objectid . " ) " ;
2018-07-02 10:09:56 +02:00
$sql .= " AND dbt. " . $dbt_keyfield . " = " . $user -> socid ;
2015-05-03 14:41:51 +02:00
}
// If internal user: Check permission for internal users that are restricted on their objects
else if ( ! empty ( $conf -> societe -> enabled ) && ( $user -> rights -> societe -> lire && ! $user -> rights -> societe -> client -> voir ))
{
if ( empty ( $dbt_keyfield )) dol_print_error ( '' , 'Param dbt_keyfield is required but not defined' );
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(sc.fk_soc) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
$sql .= " , " . MAIN_DB_PREFIX . " societe as s " ;
$sql .= " , " . MAIN_DB_PREFIX . " societe_commerciaux as sc " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND sc.fk_soc = dbt. " . $dbt_keyfield ;
$sql .= " AND dbt. " . $dbt_keyfield . " = s.rowid " ;
2018-01-16 19:52:14 +01:00
$sql .= " AND dbt.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND sc.fk_user = " . $user -> id ;
}
// If multicompany and internal users with all permissions, check user is in correct entity
else if ( ! empty ( $conf -> multicompany -> enabled ))
{
2017-12-18 15:39:40 +01:00
$sql = " SELECT COUNT(dbt. " . $dbt_select . " ) as nb " ;
2015-05-03 14:41:51 +02:00
$sql .= " FROM " . MAIN_DB_PREFIX . $dbtablename . " as dbt " ;
2017-12-18 15:39:40 +01:00
$sql .= " WHERE dbt. " . $dbt_select . " IN ( " . $objectid . " ) " ;
2015-05-03 14:41:51 +02:00
$sql .= " AND dbt.entity IN ( " . getEntity ( $sharedelement , 1 ) . " ) " ;
}
}
if ( $sql )
{
$resql = $db -> query ( $sql );
if ( $resql )
{
2017-12-18 15:39:40 +01:00
$obj = $db -> fetch_object ( $resql );
if ( ! $obj || $obj -> nb < count ( explode ( ',' , $objectid ))) return false ;
2015-05-03 14:41:51 +02:00
}
else
{
return false ;
}
}
}
return true ;
}
2012-02-12 17:41:28 +01:00
/**
* Show a message to say access is forbidden and stop program
* Calling this function terminate execution of PHP .
*
* @ param string $message Force error message
* @ param int $printheader Show header before
* @ param int $printfooter Show footer after
* @ param int $showonlymessage Show only message parameter . Otherwise add more information .
* @ return void
*/
function accessforbidden ( $message = '' , $printheader = 1 , $printfooter = 1 , $showonlymessage = 0 )
{
2018-10-29 18:19:40 +01:00
global $conf , $db , $user , $langs ;
if ( ! is_object ( $langs ))
{
include_once DOL_DOCUMENT_ROOT . '/core/class/translate.class.php' ;
$langs = new Translate ( '' , $conf );
}
$langs -> load ( " errors " );
if ( $printheader )
{
if ( function_exists ( " llxHeader " )) llxHeader ( '' );
else if ( function_exists ( " llxHeaderVierge " )) llxHeaderVierge ( '' );
}
print '<div class="error">' ;
if ( ! $message ) print $langs -> trans ( " ErrorForbidden " );
else print $message ;
print '</div>' ;
print '<br>' ;
if ( empty ( $showonlymessage ))
{
if ( $user -> login )
{
print $langs -> trans ( " CurrentLogin " ) . ': <font class="error">' . $user -> login . '</font><br>' ;
print $langs -> trans ( " ErrorForbidden2 " , $langs -> trans ( " Home " ), $langs -> trans ( " Users " ));
}
else
{
print $langs -> trans ( " ErrorForbidden3 " );
}
}
if ( $printfooter && function_exists ( " llxFooter " )) llxFooter ();
exit ( 0 );
2012-02-12 17:41:28 +01:00
}