diff --git a/admin/index.php b/admin/index.php index 785f3e59b6c5b..513b17903a166 100644 --- a/admin/index.php +++ b/admin/index.php @@ -368,6 +368,10 @@ } +if (empty($CFG->passwordsaltmain)) { + print_box(get_string('upgrade197notice', 'admin')."\n".get_string('upgrade197salt', 'admin')); +} + if (defined('WARN_DISPLAY_ERRORS_ENABLED')) { echo $OUTPUT->box(get_string('displayerrorswarning', 'admin'), 'generalbox adminwarning'); } diff --git a/admin/report/security/lib.php b/admin/report/security/lib.php index a4e1928eae417..e20c7e812912a 100644 --- a/admin/report/security/lib.php +++ b/admin/report/security/lib.php @@ -49,6 +49,7 @@ function report_security_get_issue_list() { 'report_security_check_openprofiles', 'report_security_check_google', 'report_security_check_passwordpolicy', + 'report_security_check_passwordsaltmain', 'report_security_check_emailchangeconfirmation', 'report_security_check_cookiesecure', 'report_security_check_configrw', @@ -473,6 +474,35 @@ function report_security_check_configrw($detailed=false) { return $result; } +function report_security_check_passwordsaltmain($detailed=false) { + global $CFG; + + $result = new object(); + $result->issue = 'report_security_check_passwordsaltmain'; + $result->name = get_string('check_passwordsaltmain_name', 'report_security'); + $result->info = null; + $result->details = null; + $result->status = null; + $result->link = null; + + if (empty($CFG->passwordsaltmain)) { + $result->status = REPORT_SECURITY_WARNING; + $result->info = get_string('check_passwordsaltmain_warning', 'report_security'); + } else if (trim($CFG->passwordsaltmain)=='' || preg_match('/^([\w]+|[\d]+)$/i', $CFG->passwordsaltmain)) { + $result->status = REPORT_SECURITY_WARNING; + $result->info = get_string('check_passwordsaltmain_weak', 'report_security'); + } else { + $result->status = REPORT_SECURITY_OK; + $result->info = get_string('check_passwordsaltmain_ok', 'report_security'); + } + + if ($detailed) { + $result->details = get_string('check_passwordsaltmain_details', 'report_security'); + } + + return $result; +} + /** * Lists all users with XSS risk, it would be great to combine this with risk trusts in user table, * unfortunately nobody implemented user trust UI yet :-( diff --git a/admin/settings/security.php b/admin/settings/security.php index e9e97c4244418..2e74e5a6ad11f 100644 --- a/admin/settings/security.php +++ b/admin/settings/security.php @@ -47,7 +47,7 @@ $temp->add(new admin_setting_configcheckbox('cronclionly', get_string('cronclionly', 'admin'), get_string('configcronclionly', 'admin'), 0)); $temp->add(new admin_setting_configpasswordunmask('cronremotepassword', get_string('cronremotepassword', 'admin'), get_string('configcronremotepassword', 'admin'), '')); - $temp->add(new admin_setting_configcheckbox('passwordpolicy', get_string('passwordpolicy', 'admin'), get_string('configpasswordpolicy', 'admin'), 0)); + $temp->add(new admin_setting_configcheckbox('passwordpolicy', get_string('passwordpolicy', 'admin'), get_string('configpasswordpolicy', 'admin'), 1)); $temp->add(new admin_setting_configtext('minpasswordlength', get_string('minpasswordlength', 'admin'), get_string('configminpasswordlength', 'admin'), 8, PARAM_INT)); $temp->add(new admin_setting_configtext('minpassworddigits', get_string('minpassworddigits', 'admin'), get_string('configminpassworddigits', 'admin'), 1, PARAM_INT)); $temp->add(new admin_setting_configtext('minpasswordlower', get_string('minpasswordlower', 'admin'), get_string('configminpasswordlower', 'admin'), 1, PARAM_INT)); diff --git a/lang/en_utf8/admin.php b/lang/en_utf8/admin.php index fa092b8ed7c9a..b21b2fbe3590c 100644 --- a/lang/en_utf8/admin.php +++ b/lang/en_utf8/admin.php @@ -882,6 +882,12 @@ $string['uploadpicture_userupdated'] = 'Picture updated for user $a.'; $string['uploadpicture_cannotsave'] = 'Cannot save picture for user $a. Check original picture file.'; $string['updatetimezones'] = 'Update timezones'; +$string['upgrade197notice'] = '

Moodle 1.9.7 contains a number of security fixes to user passwords and backups to protect the user information on your site.
+As a result some of your settings and permissions relating to backups may have changed.
+Please see the Moodle 1.9.7 release notes for full details.

'; +$string['upgrade197noticesubject'] = 'Moodle 1.9.7 upgrade security notices'; +$string['upgrade197salt'] = 'It is also now strongly recommended that you set a password salt to greatly reduce the risk of password theft.
+Please refer to the Moodle security report for more information on this topic. The security report can be accessed by logging into your site as an administrator and go to Site Administration - Security - Site policies'; $string['upgradeerror'] = 'Unknown error upgrading $a->plugin to version $a->version, can not continue.'; $string['upgradeforumread'] = 'A new feature has been added in Moodle 1.5 to track read/unread forum posts.
To use this functionality you need to update your tables.'; $string['upgradeforumreadinfo'] = 'A new feature has been added in Moodle 1.5 to track read/unread forum posts. To use this functionality you need to update your tables with all the tracking information for existing posts. Depending on the size of your site this can take a long time (hours) and can be quite taxing on the database, so it\'s best to do it during a quiet period. However, your site will continue functioning during this upgrade and users won\'t be affected. Once you start this process you should let it finish (keep your browser window open). However, if you stop the process by closing the window: don\'t worry, you can start over.

Do you want to start the upgrading process now?'; diff --git a/lang/en_utf8/report_security.php b/lang/en_utf8/report_security.php index 455a02093694f..aa72f71bdc7db 100644 --- a/lang/en_utf8/report_security.php +++ b/lang/en_utf8/report_security.php @@ -119,6 +119,12 @@ $string['check_passwordpolicy_name'] = 'Password policy'; $string['check_passwordpolicy_ok'] = 'Password policy enabled.'; +$string['check_passwordsaltmain_name'] = 'Password salt'; +$string['check_passwordsaltmain_warning'] = 'No password salt has been set'; +$string['check_passwordsaltmain_ok'] = 'Password salt is OK'; +$string['check_passwordsaltmain_weak'] = 'Password salt is weak'; +$string['check_passwordsaltmain_details'] = '

It is strongly recommended that a password salt is set as it greatly reduces the risk of password theft.
To set a password salt add the following to your config.php file.

\$CFG->passwordsaltmain = \'arandomstringofcharacters\';

The random string of characters should be a mix of letters, numbers and other characters.

'; + $string['check_riskadmin_detailsok'] = '

Please verify the following list of system administrators:

$a'; $string['check_riskadmin_detailswarning'] = '

Please verify the following list of system administrators:

$a->admins

It is recommended to assign administrator role in system context only. Following users have unsupported admin role assignments:

$a->unsupported'; diff --git a/lib/installlib.php b/lib/installlib.php index c36bb51acb968..5af8c22bc9cf5 100644 --- a/lib/installlib.php +++ b/lib/installlib.php @@ -203,6 +203,9 @@ function install_generate_configphp($database, $cfg, $userealpath=false) { $configphp .= '$CFG->directorypermissions = 00777; // try 02777 on a server in Safe Mode'."\r\n"; $configphp .= "\r\n"; + $configphp .= '$CFG->passwordsaltmain = '.var_export(complex_random_string(), true).";\r\n"; + $configphp .= "\r\n"; + $configphp .= 'require_once("$CFG->dirroot/lib/setup.php");'."\r\n\r\n"; $configphp .= '// There is no php closing tag in this file,'."\r\n"; $configphp .= '// it is intentional because it prevents trailing whitespace problems!'."\r\n"; diff --git a/lib/moodlelib.php b/lib/moodlelib.php index 64a8ad3472e19..f0b43b7d82fc1 100644 --- a/lib/moodlelib.php +++ b/lib/moodlelib.php @@ -7553,6 +7553,30 @@ function random_string ($length=15) { return $string; } +/** + * Generate a complex random string (usefull for md5 salts) + * + * This function is based on the above {@link random_string()} however it uses a + * larger pool of characters and generates a string between 24 and 32 characters + * + * @param int $length Optional if set generates a string to exactly this length + * @return string + */ +function complex_random_string($length=null) { + $pool = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'; + $pool .= '`~!@#%^&*()_+-=[];,./<>?:{} '; + $poollen = strlen($pool); + mt_srand ((double) microtime() * 1000000); + if ($length===null) { + $length = floor(rand(24,32)); + } + $string = ''; + for ($i = 0; $i < $length; $i++) { + $string .= $pool[(mt_rand()%$poollen)]; + } + return $string; +} + /** * Given some text (which may contain HTML) and an ideal length, * this function truncates the text neatly on a word boundary if possible @@ -7564,7 +7588,6 @@ function random_string ($length=15) { * @param string $ending The string to append if the passed string is truncated * @return string $truncate - shortened string */ - function shorten_text($text, $ideal=30, $exact = false, $ending='...') { global $CFG;