functions_dolibarr.php 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. <?php
  2. /* Copyright (C) 2007-2015 Laurent Destailleur <eldy@users.sourceforge.net>
  3. * Copyright (C) 2007-2015 Regis Houssin <regis.houssin@inodbox.com>
  4. * Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
  5. * Copyright (C) 2022 Harry Winner Kamdem <harry@sense.africa>
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 3 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  19. */
  20. /**
  21. * \file htdocs/core/login/functions_dolibarr.php
  22. * \ingroup core
  23. * \brief Authentication functions for Dolibarr mode (check user on login or email and check pass)
  24. */
  25. /**
  26. * Check validity of user/password/entity
  27. * If test is ko, reason must be filled into $_SESSION["dol_loginmesg"]
  28. * Note: On critical error (hack attempt), we put a log "functions_dolibarr::check_user_password_dolibarr authentication KO"
  29. *
  30. * @param string $usertotest Login
  31. * @param string $passwordtotest Password
  32. * @param int $entitytotest Number of instance (always 1 if module multicompany not enabled)
  33. * @return string Login if OK, '' if KO
  34. */
  35. function check_user_password_dolibarr($usertotest, $passwordtotest, $entitytotest = 1)
  36. {
  37. global $db, $conf, $langs;
  38. // Force master entity in transversal mode
  39. $entity = $entitytotest;
  40. if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
  41. $entity = 1;
  42. }
  43. $login = '';
  44. if (!empty($usertotest)) {
  45. require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
  46. dol_syslog("functions_dolibarr::check_user_password_dolibarr usertotest=".$usertotest." passwordtotest=".preg_replace('/./', '*', $passwordtotest)." entitytotest=".$entitytotest);
  47. // Verification number of USER_LOGIN_FAILED
  48. $dateverificationauth = dol_time_plus_duree(dol_now(), -1, 'd');
  49. $userremoteip = getUserRemoteIP();
  50. $nbevents = 0;
  51. $sql = "SELECT COUNT(e.rowid) as nbevent";
  52. $sql .= " FROM ".MAIN_DB_PREFIX."events as e";
  53. $sql .= " WHERE e.type = 'USER_LOGIN_FAILED'";
  54. $sql .= " AND e.ip = '".$db->escape($userremoteip)."'";
  55. $sql .= " AND e.dateevent > '".$db->idate($dateverificationauth)."'";
  56. $resql = $db->query($sql);
  57. if ($resql) {
  58. $obj = $db->fetch_object($resql);
  59. if ($obj) {
  60. $nbevents = $obj->nbevent;
  61. }
  62. }
  63. if ($nbevents <= getDolGlobalInt("MAIN_SECURITY_MAX_NUMBER_FAILED_AUTH", 100)) {
  64. // If test username/password asked, we define $test=false if ko and $login var to login if ok, set also $_SESSION["dol_loginmesg"] if ko
  65. $table = MAIN_DB_PREFIX."user";
  66. $usernamecol1 = 'login';
  67. $usernamecol2 = 'email';
  68. $entitycol = 'entity';
  69. $sql = "SELECT rowid, login, entity, pass, pass_crypted, datestartvalidity, dateendvalidity, flagdelsessionsbefore";
  70. $sql .= " FROM ".$table;
  71. $sql .= " WHERE (".$usernamecol1." = '".$db->escape($usertotest)."'";
  72. if (preg_match('/@/', $usertotest)) {
  73. $sql .= " OR ".$usernamecol2." = '".$db->escape($usertotest)."'";
  74. }
  75. $sql .= ") AND ".$entitycol." IN (0,".($entity ? ((int) $entity) : 1).")";
  76. $sql .= " AND statut = 1";
  77. // Order is required to firstly found the user into entity, then the superadmin.
  78. // For the case (TODO: we must avoid that) a user has renamed its login with same value than a user in entity 0.
  79. $sql .= " ORDER BY entity DESC";
  80. // Note: Test on validity is done later natively with isNotIntoValidityDateRange() by core after calling checkLoginPassEntity() that call this method
  81. $resql = $db->query($sql);
  82. if ($resql) {
  83. $obj = $db->fetch_object($resql);
  84. if ($obj) {
  85. $passclear = $obj->pass;
  86. $passcrypted = $obj->pass_crypted;
  87. $passtyped = $passwordtotest;
  88. $passok = false;
  89. // Check crypted password
  90. $cryptType = '';
  91. if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
  92. $cryptType = $conf->global->DATABASE_PWD_ENCRYPTED;
  93. }
  94. // By default, we use default setup for encryption rule
  95. if (!in_array($cryptType, array('auto'))) {
  96. $cryptType = 'auto';
  97. }
  98. // Check crypted password according to crypt algorithm
  99. if ($cryptType == 'auto') {
  100. if ($passcrypted && dol_verifyHash($passtyped, $passcrypted, '0')) {
  101. $passok = true;
  102. dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentification ok - hash ".$cryptType." of pass is ok");
  103. }
  104. }
  105. // For compatibility with very old versions
  106. if (!$passok) {
  107. if ((!$passcrypted || $passtyped)
  108. && ($passclear && ($passtyped == $passclear))) {
  109. $passok = true;
  110. dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentification ok - found old pass in database", LOG_WARNING);
  111. }
  112. }
  113. // Password ok ?
  114. if ($passok) {
  115. $login = $obj->login;
  116. } else {
  117. dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentication KO bad password for '".$usertotest."', cryptType=".$cryptType, LOG_NOTICE);
  118. sleep(1); // Anti brut force protection. Must be same delay when login is not valid
  119. // Load translation files required by the page
  120. $langs->loadLangs(array('main', 'errors'));
  121. $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorBadLoginPassword");
  122. }
  123. // We must check entity
  124. if ($passok && isModEnabled('multicompany')) { // We must check entity
  125. global $mc;
  126. if (!isset($mc)) {
  127. !isModEnabled('multicompany'); // Global not available, disable $conf->multicompany->enabled for safety
  128. } else {
  129. $ret = $mc->checkRight($obj->rowid, $entitytotest);
  130. if ($ret < 0) {
  131. dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentication KO entity '".$entitytotest."' not allowed for user '".$obj->rowid."'", LOG_NOTICE);
  132. $login = ''; // force authentication failure
  133. if ($mc->db->lasterror()) {
  134. $_SESSION["dol_loginmesg"] = $mc->db->lasterror();
  135. }
  136. }
  137. }
  138. }
  139. } else {
  140. dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentication KO user not found for '".$usertotest."'", LOG_NOTICE);
  141. sleep(1); // Anti brut force protection. Must be same delay when password is not valid
  142. // Load translation files required by the page
  143. $langs->loadLangs(array('main', 'errors'));
  144. $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorBadLoginPassword");
  145. }
  146. } else {
  147. dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentication KO db error for '".$usertotest."' error=".$db->lasterror(), LOG_ERR);
  148. sleep(1);
  149. $_SESSION["dol_loginmesg"] = $db->lasterror();
  150. }
  151. } else {
  152. dol_syslog("functions_dolibarr::check_user_password_dolibarr Authentication KO Too many attempts", LOG_NOTICE);
  153. sleep(1); // Anti brut force protection. Must be same delay when password is not valid
  154. // Load translation files required by the page
  155. $langs->loadLangs(array('main', 'errors'));
  156. $_SESSION["dol_loginmesg"] = $langs->transnoentitiesnoconv("ErrorTooManyAttempts");
  157. }
  158. }
  159. return $login;
  160. }