forked from Wavyzz/dolibarr
# Qual: Fix spelling for crypted and referer. The proper spelling is encrypted and referrer, but the code has some occurences where referer and crypted need to be maintained. To make verification easier, this spelling correction is limited to mostly these corrections and some minor translations and a only a few other corrections. crypted and referer are added as exceptions for spelling after this fix. Co-authored-by: Laurent Destailleur <eldy@destailleur.fr>
502 lines
17 KiB
PHP
502 lines
17 KiB
PHP
<?php
|
|
/* Copyright (C) 2004-2022 Laurent Destailleur <eldy@users.sourceforge.net>
|
|
* Copyright (C) 2005-2007 Regis Houssin <regis.houssin@inodbox.com>
|
|
* Copyright (C) 2013-2015 Juanjo Menent <jmenent@2byte.es>
|
|
*
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* \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 = true;
|
|
|
|
|
|
/*
|
|
* 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') {
|
|
//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
|
|
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);
|
|
|
|
$patternInError = false;
|
|
if ($explodePattern[0] < 1 || $explodePattern[4] < 0) {
|
|
$patternInError = true;
|
|
}
|
|
|
|
if ($explodePattern[0] < $explodePattern[1] + $explodePattern[2] + $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);
|
|
|
|
print load_fiche_titre($langs->trans("SecuritySetup"), '', 'title_setup');
|
|
|
|
print '<span class="opacitymedium">'.$langs->trans("GeneratedPasswordDesc")."</span><br>\n";
|
|
print "<br>\n";
|
|
|
|
|
|
$head = security_prepare_head();
|
|
|
|
print dol_get_fiche_head($head, 'passwords', '', -1);
|
|
|
|
print '<br>';
|
|
|
|
// Select manager to generate passwords
|
|
print '<form action="'.$_SERVER["PHP_SELF"].'" method="POST">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="update">';
|
|
print '<input type="hidden" name="constname" value="USER_PASSWORD_GENERATED">';
|
|
print '<input type="hidden" name="consttype" value="yesno">';
|
|
|
|
// Charge tableau des modules generation
|
|
$dir = "../core/modules/security/generate";
|
|
clearstatcache();
|
|
$handle = opendir($dir);
|
|
$i = 1;
|
|
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);
|
|
$arrayhandler[$obj->id] = $obj;
|
|
$i++;
|
|
}
|
|
}
|
|
closedir($handle);
|
|
}
|
|
asort($arrayhandler);
|
|
|
|
print '<div class="div-table-responsive-no-min">';
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<td colspan="2">'.$langs->trans("RuleForGeneratedPasswords").'</td>';
|
|
print '<td>'.$langs->trans("Example").'</td>';
|
|
print '<td class="center">'.$langs->trans("Activated").'</td>';
|
|
print '</tr>';
|
|
|
|
$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 '<tr class="oddeven"><td>';
|
|
print img_picto('', $module->picto, 'class="width25 size15x"').' ';
|
|
print ucfirst($key);
|
|
print "</td><td>\n";
|
|
print $module->getDescription().'<br>';
|
|
print $langs->trans("MinLength").': <span class="opacitymedium">'.$module->length.'</span>';
|
|
print '</td>';
|
|
|
|
// Show example of numbering module
|
|
print '<td class="nowraponall">';
|
|
$tmp = $module->getExample();
|
|
if (preg_match('/^Error/', $tmp)) {
|
|
$langs->load("errors");
|
|
print '<div class="error">'.$langs->trans($tmp).'</div>';
|
|
} elseif ($tmp == 'NotConfigured') {
|
|
print '<span class="opacitymedium">'.$langs->trans($tmp).'</span>';
|
|
} else {
|
|
print '<span class="opacitymedium">'.$tmp.'</span>';
|
|
}
|
|
print '</td>'."\n";
|
|
|
|
print '<td class="center">';
|
|
if ($conf->global->USER_PASSWORD_GENERATED == $key) {
|
|
//print img_picto('', 'tick');
|
|
print img_picto($langs->trans("Enabled"), 'switch_on');
|
|
} else {
|
|
print '<a href="'.$_SERVER['PHP_SELF'].'?action=setgeneraterule&token='.newToken().'&value='.$key.'">';
|
|
//print $langs->trans("Activate");
|
|
print img_picto($langs->trans("Disabled"), 'switch_off');
|
|
print '</a>';
|
|
}
|
|
print "</td></tr>\n";
|
|
}
|
|
}
|
|
print '</table>';
|
|
print '</div>';
|
|
|
|
print '</form>';
|
|
|
|
|
|
// Pattern for Password Perso
|
|
if (getDolGlobalString('USER_PASSWORD_GENERATED') == "Perso") {
|
|
print '<br>';
|
|
|
|
print '<div class="div-table-responsive-no-min">';
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<td colspan="2"> '.$langs->trans("PasswordPatternDesc").'</td>';
|
|
print '</tr>';
|
|
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("MinLength")."</td>";
|
|
print '<td><input type="number" value="'.$tabConf[0].'" id="minlenght" min="1"></td>';
|
|
print '</tr>';
|
|
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("NbMajMin")."</td>";
|
|
print '<td><input type="number" value="'.$tabConf[1].'" id="NbMajMin" min="0"></td>';
|
|
print '</tr>';
|
|
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("NbNumMin")."</td>";
|
|
print '<td><input type="number" value="'.$tabConf[2].'" id="NbNumMin" min="0"></td>';
|
|
print '</tr>';
|
|
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("NbSpeMin")."</td>";
|
|
print '<td><input type="number" value="'.$tabConf[3].'" id="NbSpeMin" min="0"></td>';
|
|
print '</tr>';
|
|
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("NbIteConsecutive")."</td>";
|
|
print '<td><input type="number" value="'.$tabConf[4].'" id="NbIteConsecutive" min="0"></td>';
|
|
print '</tr>';
|
|
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td>'.$langs->trans("NoAmbiCaracAutoGeneration")."</td>";
|
|
print '<td><input type="checkbox" id="NoAmbiCaracAutoGeneration" '.($tabConf[5] ? "checked" : "").' min="0"> <label for="NoAmbiCaracAutoGeneration" id="textcheckbox">'.($tabConf[5] ? $langs->trans("Activated") : $langs->trans("Disabled")).'</label></td>';
|
|
print '</tr>';
|
|
|
|
print '</table>';
|
|
|
|
print '<div class="center">';
|
|
print '<a class="button button-save" id="linkChangePattern">'.$langs->trans("Save").'</a>';
|
|
print '</div>';
|
|
|
|
print '<br><br>';
|
|
|
|
print '<script type="text/javascript">';
|
|
print ' function getStringArg(){';
|
|
print ' var pattern = "";';
|
|
print ' pattern += $("#minlenght").val() + ";";';
|
|
print ' pattern += $("#NbMajMin").val() + ";";';
|
|
print ' pattern += $("#NbNumMin").val() + ";";';
|
|
print ' pattern += $("#NbSpeMin").val() + ";";';
|
|
print ' pattern += $("#NbIteConsecutive").val() + ";";';
|
|
print ' pattern += $("#NoAmbiCaracAutoGeneration")[0].checked ? "1" : "0";';
|
|
print ' return pattern;';
|
|
print ' }';
|
|
|
|
print ' function valuePossible(){';
|
|
print ' var fields = ["#minlenght", "#NbMajMin", "#NbNumMin", "#NbSpeMin", "#NbIteConsecutive"];';
|
|
print ' for(var i = 0 ; i < fields.length ; i++){';
|
|
print ' if($(fields[i]).val() < $(fields[i]).attr("min")){';
|
|
print ' return false;';
|
|
print ' }';
|
|
print ' }';
|
|
print ' ';
|
|
print ' var length = parseInt($("#minlenght").val());';
|
|
print ' var length_mini = parseInt($("#NbMajMin").val()) + parseInt($("#NbNumMin").val()) + parseInt($("#NbSpeMin").val());';
|
|
print ' return length >= length_mini;';
|
|
print ' }';
|
|
|
|
print ' function generatelink(){';
|
|
print ' return "security.php?action=updatepattern&token='.newToken().'&pattern="+getStringArg();';
|
|
print ' }';
|
|
|
|
print ' function valuePatternChange(){';
|
|
print ' console.log("valuePatternChange");';
|
|
print ' var lang_save = "'.$langs->trans("Save").'";';
|
|
print ' var lang_error = "'.$langs->trans("Error").'";';
|
|
print ' var lang_Disabled = "'.$langs->trans("Disabled").'";';
|
|
print ' var lang_Activated = "'.$langs->trans("Activated").'";';
|
|
print ' $("#textcheckbox").html($("#NoAmbiCaracAutoGeneration")[0].checked ? unescape(lang_Activated) : unescape(lang_Disabled));';
|
|
print ' if(valuePossible()){';
|
|
print ' $("#linkChangePattern").attr("href",generatelink()).text(lang_save);';
|
|
print ' }';
|
|
print ' else{';
|
|
print ' $("#linkChangePattern").attr("href", null).text(lang_error);';
|
|
print ' }';
|
|
print ' }';
|
|
|
|
print ' $("#minlenght").change(function(){valuePatternChange();});';
|
|
print ' $("#NbMajMin").change(function(){valuePatternChange();});';
|
|
print ' $("#NbNumMin").change(function(){valuePatternChange();});';
|
|
print ' $("#NbSpeMin").change(function(){valuePatternChange();});';
|
|
print ' $("#NbIteConsecutive").change(function(){valuePatternChange();});';
|
|
print ' $("#NoAmbiCaracAutoGeneration").change(function(){valuePatternChange();});';
|
|
|
|
print '</script>';
|
|
}
|
|
|
|
|
|
// Crypt passwords in database
|
|
|
|
print '<br>';
|
|
print '<form method="post" action="'.$_SERVER["PHP_SELF"].'">';
|
|
print '<input type="hidden" name="token" value="'.newToken().'">';
|
|
print '<input type="hidden" name="action" value="encrypt">';
|
|
|
|
print '<table class="noborder centpercent">';
|
|
print '<tr class="liste_titre">';
|
|
print '<td colspan="3">'.$langs->trans("Parameters").'</td>';
|
|
print '<td class="center">'.$langs->trans("Activated").'</td>';
|
|
print '<td class="center"></td>';
|
|
print '</tr>';
|
|
|
|
// Disable clear password in database
|
|
print '<tr class="oddeven">';
|
|
print '<td colspan="3">'.$langs->trans("DoNotStoreClearPassword").'</td>';
|
|
print '<td class="center" width="60">';
|
|
if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
|
|
print img_picto($langs->trans("Active"), 'tick');
|
|
}
|
|
print '</td>';
|
|
if (!getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
|
|
print '<td class="center" width="100">';
|
|
print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=activate_encrypt&token='.newToken().'">'.$langs->trans("Activate").'</a>';
|
|
print "</td>";
|
|
}
|
|
|
|
// Database conf file encryption
|
|
if (getDolGlobalString('DATABASE_PWD_ENCRYPTED')) {
|
|
print '<td class="center" width="100">';
|
|
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 '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=disable_encrypt&token='.newToken().'">'.$langs->trans("Disable").'</a>';
|
|
} else {
|
|
print '-';
|
|
}
|
|
print "</td>";
|
|
}
|
|
print "</td>";
|
|
print '</tr>';
|
|
|
|
|
|
// Crypt password into config file conf.php
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td colspan="3">'.$langs->trans("MainDbPasswordFileConfEncrypted").'</td>';
|
|
print '<td align="center" width="60">';
|
|
if (preg_match('/crypted:/i', $dolibarr_main_db_pass) || !empty($dolibarr_main_db_encrypted_pass)) {
|
|
print img_picto($langs->trans("Active"), 'tick');
|
|
}
|
|
|
|
print '</td>';
|
|
|
|
print '<td class="center" width="100">';
|
|
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 '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=activate_encryptdbpassconf&token='.newToken().'">'.$langs->trans("Activate").'</a>';
|
|
}
|
|
if (!empty($dolibarr_main_db_encrypted_pass)) {
|
|
print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=disable_encryptdbpassconf&token='.newToken().'">'.$langs->trans("Disable").'</a>';
|
|
}
|
|
}
|
|
print "</td>";
|
|
|
|
print "</td>";
|
|
print '</tr>';
|
|
|
|
|
|
// Disable link "Forget password" on logon
|
|
|
|
print '<tr class="oddeven">';
|
|
print '<td colspan="3">'.$langs->trans("DisableForgetPasswordLinkOnLogonPage").'</td>';
|
|
print '<td class="center" width="60">';
|
|
if (getDolGlobalString('MAIN_SECURITY_DISABLEFORGETPASSLINK')) {
|
|
print img_picto($langs->trans("Active"), 'tick');
|
|
}
|
|
print '</td>';
|
|
if (!getDolGlobalString('MAIN_SECURITY_DISABLEFORGETPASSLINK')) {
|
|
print '<td class="center" width="100">';
|
|
print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=activate_MAIN_SECURITY_DISABLEFORGETPASSLINK&token='.newToken().'">'.$langs->trans("Activate").'</a>';
|
|
print "</td>";
|
|
}
|
|
if (getDolGlobalString('MAIN_SECURITY_DISABLEFORGETPASSLINK')) {
|
|
print '<td center="center" width="100">';
|
|
print '<a class="reposition" href="'.$_SERVER["PHP_SELF"].'?action=disable_MAIN_SECURITY_DISABLEFORGETPASSLINK&token='.newToken().'">'.$langs->trans("Disable").'</a>';
|
|
print "</td>";
|
|
}
|
|
print "</td>";
|
|
print '</tr>';
|
|
|
|
|
|
print '</table>';
|
|
|
|
print '</form>';
|
|
|
|
print '<br>';
|
|
|
|
if (GETPOST('info', 'int') > 0) {
|
|
if (function_exists('password_hash')) {
|
|
print $langs->trans("Note: The function password_hash exists on your PHP")."<br>\n";
|
|
} else {
|
|
print $langs->trans("Note: The function password_hash does not exists on your PHP")."<br>\n";
|
|
}
|
|
print 'MAIN_SECURITY_HASH_ALGO = '.getDolGlobalString('MAIN_SECURITY_HASH_ALGO')."<br>\n";
|
|
print 'MAIN_SECURITY_SALT = '.getDolGlobalString('MAIN_SECURITY_SALT')."<br>\n";
|
|
}
|
|
|
|
print '</div>';
|
|
|
|
// End of page
|
|
llxFooter();
|
|
$db->close();
|