PageRenderTime 46ms CodeModel.GetById 15ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/asterix14/dolibarr
PHP | 540 lines | 368 code | 66 blank | 106 comment | 69 complexity | 332398731daab9623ad98dbb01f231cb MD5 | raw file
Possible License(s): LGPL-2.0
  1. <?php
  2. /* Copyright (C) 2008-2011 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2008-2011 Regis Houssin <regis@dolibarr.fr>
  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 2 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.
  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. * Return a login if login/pass was successfull
  28. *
  29. * @param string $usertotest Login value to test
  30. * @param string $passwordtotest Password value to test
  31. * @param string $entitytotest Instance of data we must check
  32. * @param array $authmode Array list of selected authentication mode array('http', 'dolibarr', 'xxx'...)
  33. * @return string Login or ''
  34. */
  35. function checkLoginPassEntity($usertotest,$passwordtotest,$entitytotest,$authmode)
  36. {
  37. global $conf,$langs;
  38. global $dolauthmode; // To return authentication finally used
  39. // Check parameetrs
  40. if ($entitytotest == '') $entitytotest=1;
  41. dol_syslog("checkLoginPassEntity usertotest=".$usertotest." entitytotest=".$entitytotest." authmode=".join(',',$authmode));
  42. $login = '';
  43. // Validation of login/pass/entity with a third party login module method
  44. if (! empty($conf->login_method_modules) && is_array($conf->login_method_modules))
  45. {
  46. foreach($conf->login_method_modules as $dir)
  47. {
  48. $newdir=dol_osencode($dir);
  49. // Check if directory exists
  50. if (! is_dir($newdir)) continue;
  51. $handle=opendir($newdir);
  52. if (is_resource($handle))
  53. {
  54. while (($file = readdir($handle))!==false)
  55. {
  56. if (is_readable($dir.'/'.$file) && preg_match('/^functions_([^_]+)\.php/',$file,$reg))
  57. {
  58. $authfile = $dir.'/'.$file;
  59. $mode = $reg[1];
  60. $result=include_once($authfile);
  61. if ($result)
  62. {
  63. // Call function to check user/password
  64. $function='check_user_password_'.$mode;
  65. $login=call_user_func($function,$usertotest,$passwordtotest,$entitytotest);
  66. if ($login)
  67. {
  68. $conf->authmode=$mode; // This properties is defined only when logged to say what mode was successfully used
  69. }
  70. }
  71. else
  72. {
  73. dol_syslog("Authentification ko - failed to load file '".$authfile."'",LOG_ERR);
  74. sleep(1); // To slow brut force cracking
  75. $langs->load('main');
  76. $langs->load('other');
  77. $_SESSION["dol_loginmesg"]=$langs->trans("ErrorFailedToLoadLoginFileForMode",$mode);
  78. }
  79. }
  80. }
  81. closedir($handle);
  82. }
  83. }
  84. }
  85. // Validation of login/pass/entity with standard modules
  86. if (empty($login))
  87. {
  88. $test=true;
  89. foreach($authmode as $mode)
  90. {
  91. if ($test && $mode && ! $login)
  92. {
  93. $mode=trim($mode);
  94. $authfile=DOL_DOCUMENT_ROOT.'/core/login/functions_'.$mode.'.php';
  95. $result=include_once($authfile);
  96. if ($result)
  97. {
  98. // Call function to check user/password
  99. $function='check_user_password_'.$mode;
  100. $login=call_user_func($function,$usertotest,$passwordtotest,$entitytotest);
  101. if ($login) // Login is successfull
  102. {
  103. $test=false; // To stop once at first login success
  104. $conf->authmode=$mode; // This properties is defined only when logged to say what mode was successfully used
  105. $dol_tz=$_POST["tz"];
  106. $dol_dst=$_POST["dst"];
  107. $dol_screenwidth=$_POST["screenwidth"];
  108. $dol_screenheight=$_POST["screenheight"];
  109. }
  110. }
  111. else
  112. {
  113. dol_syslog("Authentification ko - failed to load file '".$authfile."'",LOG_ERR);
  114. sleep(1);
  115. $langs->load('main');
  116. $langs->load('other');
  117. $_SESSION["dol_loginmesg"]=$langs->trans("ErrorFailedToLoadLoginFileForMode",$mode);
  118. }
  119. }
  120. }
  121. }
  122. return $login;
  123. }
  124. /**
  125. * Show Dolibarr default login page
  126. *
  127. * @param Translate $langs Lang object (must be initialized by a new).
  128. * @param Conf $conf Conf object
  129. * @param Societe $mysoc Company object
  130. * @return void
  131. */
  132. function dol_loginfunction($langs,$conf,$mysoc)
  133. {
  134. global $dolibarr_main_demo,$db;
  135. global $smartphone;
  136. $langcode=(GETPOST('lang')?((is_object($langs)&&$langs->defaultlang)?$langs->defaultlang:'auto'):GETPOST('lang'));
  137. $langs->setDefaultLang($langcode);
  138. $langs->load("main");
  139. $langs->load("other");
  140. $langs->load("help");
  141. $langs->load("admin");
  142. $main_authentication=$conf->file->main_authentication;
  143. $session_name=session_name();
  144. $dol_url_root = DOL_URL_ROOT;
  145. $php_self = $_SERVER['PHP_SELF'];
  146. $php_self.= $_SERVER["QUERY_STRING"]?'?'.$_SERVER["QUERY_STRING"]:'';
  147. // Title
  148. $title='Dolibarr '.DOL_VERSION;
  149. if (! empty($conf->global->MAIN_APPLICATION_TITLE)) $title=$conf->global->MAIN_APPLICATION_TITLE;
  150. // Select templates
  151. if (preg_match('/^smartphone/',$conf->smart_menu) && isset($conf->browser->phone))
  152. {
  153. $template_dir = DOL_DOCUMENT_ROOT.'/theme/phones/smartphone/tpl/';
  154. }
  155. else
  156. {
  157. if (file_exists(DOL_DOCUMENT_ROOT."/theme/".$conf->theme."/tpl/login.tpl.php"))
  158. {
  159. $template_dir = DOL_DOCUMENT_ROOT."/theme/".$conf->theme."/tpl/";
  160. }
  161. else
  162. {
  163. $template_dir = DOL_DOCUMENT_ROOT."/core/tpl/";
  164. }
  165. }
  166. $conf->css = "/theme/".$conf->theme."/style.css.php?lang=".$langs->defaultlang;
  167. $conf_css = DOL_URL_ROOT.$conf->css;
  168. // Set cookie for timeout management
  169. $prefix=dol_getprefix();
  170. $sessiontimeout='DOLSESSTIMEOUT_'.$prefix;
  171. if (! empty($conf->global->MAIN_SESSION_TIMEOUT)) setcookie($sessiontimeout, $conf->global->MAIN_SESSION_TIMEOUT, 0, "/", '', 0);
  172. if (GETPOST("urlfrom")) $_SESSION["urlfrom"]=GETPOST("urlfrom");
  173. else unset($_SESSION["urlfrom"]);
  174. if (! GETPOST("username")) $focus_element='username';
  175. else $focus_element='password';
  176. $login_background=DOL_URL_ROOT.'/theme/login_background.png';
  177. if (file_exists(DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/login_background.png'))
  178. {
  179. $login_background=DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/login_background.png';
  180. }
  181. $demologin='';
  182. $demopassword='';
  183. if (! empty($dolibarr_main_demo))
  184. {
  185. $tab=explode(',',$dolibarr_main_demo);
  186. $demologin=$tab[0];
  187. $demopassword=$tab[1];
  188. }
  189. // Entity cookie
  190. if (! empty($conf->global->MAIN_MODULE_MULTICOMPANY))
  191. {
  192. $lastuser = '';
  193. $lastentity = $_POST['entity'];
  194. if (! empty($conf->global->MAIN_MULTICOMPANY_COOKIE))
  195. {
  196. $prefix=dol_getprefix();
  197. $entityCookieName = 'DOLENTITYID_'.$prefix;
  198. if (isset($_COOKIE[$entityCookieName]))
  199. {
  200. include_once(DOL_DOCUMENT_ROOT . "/core/class/cookie.class.php");
  201. $cryptkey = (! empty($conf->file->cookie_cryptkey) ? $conf->file->cookie_cryptkey : '' );
  202. $entityCookie = new DolCookie($cryptkey);
  203. $cookieValue = $entityCookie->_getCookie($entityCookieName);
  204. list($lastuser, $lastentity) = explode('|', $cookieValue);
  205. }
  206. }
  207. }
  208. // Login
  209. $login = (!empty($lastuser)?$lastuser:(GETPOST("username","alpha",2)?GETPOST("username","alpha",2):$demologin));
  210. $password = $demopassword;
  211. // Show logo (search in order: small company logo, large company logo, theme logo, common logo)
  212. $width=0;
  213. $rowspan=2;
  214. $urllogo=DOL_URL_ROOT.'/theme/login_logo.png';
  215. if (! empty($mysoc->logo_small) && is_readable($conf->mycompany->dir_output.'/logos/thumbs/'.$mysoc->logo_small))
  216. {
  217. $urllogo=DOL_URL_ROOT.'/viewimage.php?cache=1&amp;modulepart=companylogo&amp;file='.urlencode('thumbs/'.$mysoc->logo_small);
  218. }
  219. elseif (! empty($mysoc->logo) && is_readable($conf->mycompany->dir_output.'/logos/'.$mysoc->logo))
  220. {
  221. $urllogo=DOL_URL_ROOT.'/viewimage.php?cache=1&amp;modulepart=companylogo&amp;file='.urlencode($mysoc->logo);
  222. $width=128;
  223. }
  224. elseif (is_readable(DOL_DOCUMENT_ROOT.'/theme/'.$conf->theme.'/img/dolibarr_logo.png'))
  225. {
  226. $urllogo=DOL_URL_ROOT.'/theme/'.$conf->theme.'/img/dolibarr_logo.png';
  227. }
  228. elseif (is_readable(DOL_DOCUMENT_ROOT.'/theme/dolibarr_logo.png'))
  229. {
  230. $urllogo=DOL_URL_ROOT.'/theme/dolibarr_logo.png';
  231. }
  232. // Entity field
  233. $select_entity='';
  234. if (! empty($conf->global->MAIN_MODULE_MULTICOMPANY) && empty($conf->global->MULTICOMPANY_HIDE_LOGIN_COMBOBOX))
  235. {
  236. $rowspan++;
  237. $res=dol_include_once('/multicompany/class/actions_multicompany.class.php');
  238. if ($res)
  239. {
  240. $mc = new ActionsMulticompany($db);
  241. $select_entity=$mc->select_entities($lastentity, 'tabindex="3"', 1);
  242. }
  243. }
  244. // Security graphical code
  245. $captcha=0;
  246. $captcha_refresh='';
  247. if (function_exists("imagecreatefrompng") && ! empty($conf->global->MAIN_SECURITY_ENABLECAPTCHA))
  248. {
  249. $captcha=1;
  250. $captcha_refresh=img_picto($langs->trans("Refresh"),'refresh');
  251. }
  252. // Extra link
  253. $forgetpasslink=0;
  254. $helpcenterlink=0;
  255. if (empty($conf->global->MAIN_SECURITY_DISABLEFORGETPASSLINK) || empty($conf->global->MAIN_HELPCENTER_DISABLELINK))
  256. {
  257. if (empty($conf->global->MAIN_SECURITY_DISABLEFORGETPASSLINK))
  258. {
  259. $forgetpasslink=1;
  260. }
  261. if (empty($conf->global->MAIN_HELPCENTER_DISABLELINK))
  262. {
  263. $helpcenterlink=1;
  264. }
  265. }
  266. // Home message
  267. if (! empty($conf->global->MAIN_HOME))
  268. {
  269. $i=0;
  270. while (preg_match('/__\(([a-zA-Z]+)\)__/i',$conf->global->MAIN_HOME,$reg) && $i < 100)
  271. {
  272. $conf->global->MAIN_HOME=preg_replace('/__\('.$reg[1].'\)__/i',$langs->trans($reg[1]),$conf->global->MAIN_HOME);
  273. $i++;
  274. }
  275. }
  276. $main_home=dol_htmlcleanlastbr($conf->global->MAIN_HOME);
  277. // Google AD
  278. $main_google_ad_client = ((! empty($conf->global->MAIN_GOOGLE_AD_CLIENT) && ! empty($conf->global->MAIN_GOOGLE_AD_SLOT))?1:0);
  279. $dol_loginmesg = $_SESSION["dol_loginmesg"];
  280. include($template_dir.'login.tpl.php'); // To use native PHP
  281. $_SESSION["dol_loginmesg"] = '';
  282. }
  283. /**
  284. * Fonction pour initialiser un salt pour la fonction crypt.
  285. *
  286. * @param int $type 2=>renvoi un salt pour cryptage DES
  287. * 12=>renvoi un salt pour cryptage MD5
  288. * non defini=>renvoi un salt pour cryptage par defaut
  289. * @return string Salt string
  290. */
  291. function makesalt($type=CRYPT_SALT_LENGTH)
  292. {
  293. dol_syslog("security.lib.php::makesalt type=".$type);
  294. switch($type)
  295. {
  296. case 12: // 8 + 4
  297. $saltlen=8; $saltprefix='$1$'; $saltsuffix='$'; break;
  298. case 8: // 8 (Pour compatibilite, ne devrait pas etre utilise)
  299. $saltlen=8; $saltprefix='$1$'; $saltsuffix='$'; break;
  300. case 2: // 2
  301. default: // by default, fall back on Standard DES (should work everywhere)
  302. $saltlen=2; $saltprefix=''; $saltsuffix=''; break;
  303. }
  304. $salt='';
  305. while(dol_strlen($salt) < $saltlen) $salt.=chr(mt_rand(64,126));
  306. $result=$saltprefix.$salt.$saltsuffix;
  307. dol_syslog("security.lib.php::makesalt return=".$result);
  308. return $result;
  309. }
  310. /**
  311. * Encode or decode database password in config file
  312. *
  313. * @param int $level Encode level: 0 no encoding, 1 encoding
  314. * @return int <0 if KO, >0 if OK
  315. */
  316. function encodedecode_dbpassconf($level=0)
  317. {
  318. dol_syslog("security.lib::encodedecode_dbpassconf level=".$level, LOG_DEBUG);
  319. $config = '';
  320. $passwd='';
  321. $passwd_crypted='';
  322. if ($fp = fopen(DOL_DOCUMENT_ROOT.'/conf/conf.php','r'))
  323. {
  324. while(!feof($fp))
  325. {
  326. $buffer = fgets($fp,4096);
  327. $lineofpass=0;
  328. if (preg_match('/^[^#]*dolibarr_main_db_encrypted_pass[\s]*=[\s]*(.*)/i',$buffer,$reg)) // Old way to save crypted value
  329. {
  330. $val = trim($reg[1]); // This also remove CR/LF
  331. $val=preg_replace('/^["\']/','',$val);
  332. $val=preg_replace('/["\'][\s;]*$/','',$val);
  333. if (! empty($val))
  334. {
  335. $passwd_crypted = $val;
  336. $val = dol_decode($val);
  337. $passwd = $val;
  338. $lineofpass=1;
  339. }
  340. }
  341. elseif (preg_match('/^[^#]*dolibarr_main_db_pass[\s]*=[\s]*(.*)/i',$buffer,$reg))
  342. {
  343. $val = trim($reg[1]); // This also remove CR/LF
  344. $val=preg_replace('/^["\']/','',$val);
  345. $val=preg_replace('/["\'][\s;]*$/','',$val);
  346. if (preg_match('/crypted:/i',$buffer))
  347. {
  348. $val = preg_replace('/crypted:/i','',$val);
  349. $passwd_crypted = $val;
  350. $val = dol_decode($val);
  351. $passwd = $val;
  352. }
  353. else
  354. {
  355. $passwd = $val;
  356. $val = dol_encode($val);
  357. $passwd_crypted = $val;
  358. }
  359. $lineofpass=1;
  360. }
  361. // Output line
  362. if ($lineofpass)
  363. {
  364. // Add value at end of file
  365. if ($level == 0)
  366. {
  367. $config .= '$dolibarr_main_db_pass="'.$passwd.'";'."\n";
  368. }
  369. if ($level == 1)
  370. {
  371. $config .= '$dolibarr_main_db_pass="crypted:'.$passwd_crypted.'";'."\n";
  372. }
  373. //print 'passwd = '.$passwd.' - passwd_crypted = '.$passwd_crypted;
  374. //exit;
  375. }
  376. else
  377. {
  378. $config .= $buffer;
  379. }
  380. }
  381. fclose($fp);
  382. // Write new conf file
  383. $file=DOL_DOCUMENT_ROOT.'/conf/conf.php';
  384. if ($fp = @fopen($file,'w'))
  385. {
  386. fputs($fp, $config, dol_strlen($config));
  387. fclose($fp);
  388. // It's config file, so we set read permission for creator only.
  389. // Should set permission to web user and groups for users used by batch
  390. //@chmod($file, octdec('0600'));
  391. return 1;
  392. }
  393. else
  394. {
  395. dol_syslog("security.lib::encodedecode_dbpassconf Failed to open conf.php file for writing", LOG_WARNING);
  396. return -1;
  397. }
  398. }
  399. else
  400. {
  401. dol_syslog("security.lib::encodedecode_dbpassconf Failed to read conf.php", LOG_ERR);
  402. return -2;
  403. }
  404. }
  405. /**
  406. * Encode a string
  407. *
  408. * @param string $chain chaine de caracteres a encoder
  409. * @return string chaine de caracteres encodees
  410. */
  411. function dol_encode($chain)
  412. {
  413. $strlength=dol_strlen($chain);
  414. for ($i=0; $i < $strlength; $i++)
  415. {
  416. $output_tab[$i] = chr(ord(substr($chain,$i,1))+17);
  417. }
  418. $string_coded = base64_encode(implode("",$output_tab));
  419. return $string_coded;
  420. }
  421. /**
  422. * Decode a string
  423. *
  424. * @param string $chain chaine de caracteres a decoder
  425. * @return string chaine de caracteres decodee
  426. */
  427. function dol_decode($chain)
  428. {
  429. $chain = base64_decode($chain);
  430. $strlength=dol_strlen($chain);
  431. for($i=0; $i < $strlength;$i++)
  432. {
  433. $output_tab[$i] = chr(ord(substr($chain,$i,1))-17);
  434. }
  435. $string_decoded = implode("",$output_tab);
  436. return $string_decoded;
  437. }
  438. /**
  439. * Return a generated password using default module
  440. *
  441. * @param boolean $generic true=Create generic password (a MD5 string), false=Use the configured password generation module
  442. * @return string New value for password
  443. */
  444. function getRandomPassword($generic=false)
  445. {
  446. global $db,$conf,$langs,$user;
  447. $generated_password='';
  448. if ($generic) $generated_password=dol_hash(mt_rand());
  449. else if ($conf->global->USER_PASSWORD_GENERATED)
  450. {
  451. $nomclass="modGeneratePass".ucfirst($conf->global->USER_PASSWORD_GENERATED);
  452. $nomfichier=$nomclass.".class.php";
  453. //print DOL_DOCUMENT_ROOT."/core/modules/security/generate/".$nomclass;
  454. require_once(DOL_DOCUMENT_ROOT."/core/modules/security/generate/".$nomfichier);
  455. $genhandler=new $nomclass($db,$conf,$langs,$user);
  456. $generated_password=$genhandler->getNewGeneratedPassword();
  457. unset($genhandler);
  458. }
  459. return $generated_password;
  460. }
  461. /**
  462. * Returns a hash of a string
  463. *
  464. * @param string $chain String to hash
  465. * @param int $type Type of hash (0:md5, 1:sha1, 2:sha1+md5)
  466. * @return string Hash of string
  467. */
  468. function dol_hash($chain,$type=0)
  469. {
  470. if ($type == 1) return sha1($chain);
  471. else if ($type == 2) return sha1(md5($chain));
  472. else return md5($chain);
  473. }
  474. ?>