* Copyright (C) 2005-2007 Regis Houssin * Copyright (C) 2013-2015 Juanjo Menent * Copyright (C) 2024 MDW * * 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 * the Free Software Foundation; either version 3 of the License, or * (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 * along with this program. If not, see . */ /** * \file htdocs/admin/security.php * \ingroup setup * \brief Page of setup of security */ // Load Dolibarr environment require '../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; $action = GETPOST('action', 'aZ09'); // Load translation files required by the page $langs->loadLangs(array("users", "admin", "other")); if (!$user->admin) { accessforbidden(); } // Allow/Disallow change to clear passwords once passwords are encrypted $allow_disable_encryption = false; /* * Actions */ if ($action == 'setgeneraterule') { if (!dolibarr_set_const($db, 'USER_PASSWORD_GENERATED', GETPOST("value", "alphanohtml"), 'chaine', 0, '', $conf->entity)) { dol_print_error($db); } } if ($action == 'activate_encrypt') { $error = 0; $db->begin(); // On old version, a bug created the constant into user entity, so we delete it to be sure such entry won't exists. We want it in entity 0 or nowhere. dolibarr_del_const($db, "DATABASE_PWD_ENCRYPTED", $conf->entity); // We set entity=0 (all) because DATABASE_PWD_ENCRYPTED is a setup into conf file, so always shared for everybody $entityforall = 0; dolibarr_set_const($db, "DATABASE_PWD_ENCRYPTED", "1", 'chaine', 0, '', $entityforall); $sql = "SELECT u.rowid, u.pass, u.pass_crypted"; $sql .= " FROM ".MAIN_DB_PREFIX."user as u"; $sql .= " WHERE u.pass IS NOT NULL AND LENGTH(u.pass) < 32"; // Not a MD5 value $resql = $db->query($sql); if ($resql) { $numrows = $db->num_rows($resql); $i = 0; while ($i < $numrows) { $obj = $db->fetch_object($resql); if (dol_hash($obj->pass)) { $sql = "UPDATE ".MAIN_DB_PREFIX."user"; $sql .= " SET pass_crypted = '".dol_hash($obj->pass)."', pass = NULL"; $sql .= " WHERE rowid=".((int) $obj->rowid); //print $sql; $resql2 = $db->query($sql); if (!$resql2) { dol_print_error($db); $error++; break; } $i++; } } } else { dol_print_error($db); } //print $error." ".$sql; //exit; if (!$error) { $db->commit(); } else { $db->rollback(); dol_print_error($db, ''); } } elseif ($action == 'disable_encrypt') { // By default, $allow_disable_encryption is false we do not allow to disable encryption because passwords can't be decoded once encrypted. if ($allow_disable_encryption) { dolibarr_del_const($db, "DATABASE_PWD_ENCRYPTED", $conf->entity); } } if ($action == 'activate_encryptdbpassconf') { $result = encodedecode_dbpassconf(1); if ($result > 0) { sleep(3); // Don't know why but we need to wait file is completely saved before making the reload. Even with flush and clearstatcache, we need to wait. // database value not required //dolibarr_set_const($db, "MAIN_DATABASE_PWD_CONFIG_ENCRYPTED", "1"); header("Location: security.php"); exit; } else { setEventMessages($langs->trans('InstrucToEncodePass', dol_encode($dolibarr_main_db_pass)), null, 'warnings'); } } elseif ($action == 'disable_encryptdbpassconf') { $result = encodedecode_dbpassconf(0); if ($result > 0) { sleep(3); // Don't know why but we need to wait file is completely saved before making the reload. Even with flush and clearstatcache, we need to wait. // database value not required //dolibarr_del_const($db, "MAIN_DATABASE_PWD_CONFIG_ENCRYPTED",$conf->entity); header("Location: security.php"); exit; } else { //setEventMessages($langs->trans('InstrucToClearPass', $dolibarr_main_db_pass), null, 'warnings'); setEventMessages($langs->trans('InstrucToClearPass', $langs->transnoentitiesnoconv("DatabasePassword")), null, 'warnings'); } } if ($action == 'activate_MAIN_SECURITY_DISABLEFORGETPASSLINK') { dolibarr_set_const($db, "MAIN_SECURITY_DISABLEFORGETPASSLINK", '1', 'chaine', 0, '', $conf->entity); } elseif ($action == 'disable_MAIN_SECURITY_DISABLEFORGETPASSLINK') { dolibarr_del_const($db, "MAIN_SECURITY_DISABLEFORGETPASSLINK", $conf->entity); } if ($action == 'updatepattern') { $pattern = GETPOST("pattern", "alpha"); $explodePattern = explode(';', $pattern); // List of ints separated with ';' containing counts $patternInError = false; if ((int) $explodePattern[0] < 1 || (int) $explodePattern[4] < 0) { $patternInError = true; } if ((int) $explodePattern[0] < (int) $explodePattern[1] + (int) $explodePattern[2] + (int) $explodePattern[3]) { $patternInError = true; } if (!$patternInError) { dolibarr_set_const($db, "USER_PASSWORD_PATTERN", $pattern, 'chaine', 0, '', $conf->entity); setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); header("Location: security.php"); exit; } } /* * View */ $form = new Form($db); $wikihelp = 'EN:Setup_Security|FR:Paramétrage_Sécurité|ES:Configuración_Seguridad'; llxHeader('', $langs->trans("Passwords"), $wikihelp, '', 0, 0, '', '', '', 'mod-admin page-security'); print load_fiche_titre($langs->trans("SecuritySetup"), '', 'title_setup'); print ''.$langs->trans("GeneratedPasswordDesc")."
\n"; print "
\n"; $head = security_prepare_head(); print dol_get_fiche_head($head, 'passwords', '', -1); print '
'; // Select manager to generate passwords print '
'; print ''; print ''; print ''; print ''; // Charge tableau des modules generation $dir = "../core/modules/security/generate"; clearstatcache(); $handle = opendir($dir); $i = 1; $arrayhandler = array(); if (is_resource($handle)) { while (($file = readdir($handle)) !== false) { if (preg_match('/(modGeneratePass[a-z]+)\.class\.php$/i', $file, $reg)) { // Charging the numbering class $classname = $reg[1]; require_once $dir.'/'.$file; $obj = new $classname($db, $conf, $langs, $user); '@phan-var-force ModeleGenPassword $obj'; $arrayhandler[$obj->id] = $obj; $i++; } } closedir($handle); } asort($arrayhandler); print '
'; print ''; print ''; print ''; print ''; print ''; print ''; $tabConf = explode(";", getDolGlobalString('USER_PASSWORD_PATTERN')); foreach ($arrayhandler as $key => $module) { // Show modules according to features level if (!empty($module->version) && $module->version == 'development' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2) { continue; } if (!empty($module->version) && $module->version == 'experimental' && getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1) { continue; } if ($module->isEnabled()) { print ''; // Show example of numbering module print ''."\n"; print '\n"; } } print '
'.$langs->trans("RuleForGeneratedPasswords").''.$langs->trans("Example").''.$langs->trans("Activated").'
'; print img_picto('', $module->picto, 'class="width25 size15x marginrightonly"').' '; print ucfirst($key); print "\n"; print $module->getDescription().'
'; print $langs->trans("MinLength").': '.$module->length.''; print '
'; $tmp = $module->getExample(); if (preg_match('/^Error/', $tmp)) { $langs->load("errors"); print '
'.$langs->trans($tmp).'
'; } elseif ($tmp == 'NotConfigured') { print ''.$langs->trans($tmp).''; } else { print ''.$tmp.''; } print '
'; if ($conf->global->USER_PASSWORD_GENERATED == $key) { //print img_picto('', 'tick'); print img_picto($langs->trans("Enabled"), 'switch_on'); } else { print ''; //print $langs->trans("Activate"); print img_picto($langs->trans("Disabled"), 'switch_off'); print ''; } print "
'; print '
'; print '
'; // Pattern for Password Perso if (getDolGlobalString('USER_PASSWORD_GENERATED') == "Perso") { print '
'; print '
'; print ''; print ''; print ''; print ''; print ''; print '"; print ''; print ''; print ''; print '"; print ''; print ''; print ''; print '"; print ''; print ''; print ''; print '"; print ''; print ''; print ''; print '"; print ''; print ''; print ''; print '"; print ''; print ''; print '
'.$langs->trans("PasswordPatternDesc").'
'.$langs->trans("MinLength")."
'.$langs->trans("NbMajMin")."
'.$langs->trans("NbNumMin")."
'.$langs->trans("NbSpeMin")."
'.$langs->trans("NbIteConsecutive")."
'.$langs->trans("NoAmbiCaracAutoGeneration")."
'; print '
'; print ''.$langs->trans("Save").''; print '
'; print '

'; print ''; } // Crypt passwords in database print '
'; print '
'; print ''; print ''; print ''; print ''; print ''; print ''; print ''; print ''; // Disable clear password in database print ''; print ''; print ''; if (!getDolGlobalString('DATABASE_PWD_ENCRYPTED')) { print '"; } else { print '"; } print ""; print ''; // Crypt password into config file conf.php print ''; print ''; print ''; print '"; print ""; print ''; // Disable link "Forget password" on logon print ''; print ''; print ''; if (!getDolGlobalString('MAIN_SECURITY_DISABLEFORGETPASSLINK')) { print '"; } if (getDolGlobalString('MAIN_SECURITY_DISABLEFORGETPASSLINK')) { print '"; } print ""; print ''; print '
'.$langs->trans("Parameters").''.$langs->trans("Activated").'
'.$langs->trans("DoNotStoreClearPassword").''; if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) { print img_picto($langs->trans("Active"), 'tick'); } print ''; print ''.$langs->trans("Activate").''; print "'; if ($allow_disable_encryption) { //On n'autorise pas l'annulation de l'encryption car les mots de passe ne peuvent pas etre decodes //Do not allow "disable encryption" as passwords cannot be decrypted print ''.$langs->trans("Disable").''; } else { print ''.$langs->trans("Always").''; } print "
'.$langs->trans("MainDbPasswordFileConfEncrypted").''; if (preg_match('/crypted:/i', $dolibarr_main_db_pass) || !empty($dolibarr_main_db_encrypted_pass)) { print img_picto($langs->trans("Active"), 'tick'); } print ''; if (empty($dolibarr_main_db_pass) && empty($dolibarr_main_db_encrypted_pass)) { $langs->load("errors"); print img_warning($langs->trans("WarningPassIsEmpty")); } else { if (empty($dolibarr_main_db_encrypted_pass)) { print ''.$langs->trans("Activate").''; } if (!empty($dolibarr_main_db_encrypted_pass)) { print ''.$langs->trans("Disable").''; } } print "
'.$langs->trans("DisableForgetPasswordLinkOnLogonPage").''; if (getDolGlobalString('MAIN_SECURITY_DISABLEFORGETPASSLINK')) { print img_picto($langs->trans("Active"), 'tick'); } print ''; print ''.$langs->trans("Activate").''; print "'; print ''.$langs->trans("Disable").''; print "
'; print '
'; print '
'; if (GETPOSTINT('info') > 0) { if (function_exists('password_hash')) { print $langs->trans("Note: The function password_hash exists on your PHP")."
\n"; } else { print $langs->trans("Note: The function password_hash does not exist on your PHP")."
\n"; } print 'MAIN_SECURITY_HASH_ALGO = '.getDolGlobalString('MAIN_SECURITY_HASH_ALGO')."
\n"; print 'MAIN_SECURITY_SALT = '.getDolGlobalString('MAIN_SECURITY_SALT')."
\n"; } print '
'; // End of page llxFooter(); $db->close();