]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-17222 Security overview report - not finished yet, work in progress
authorskodak <skodak>
Mon, 29 Dec 2008 19:13:56 +0000 (19:13 +0000)
committerskodak <skodak>
Mon, 29 Dec 2008 19:13:56 +0000 (19:13 +0000)
admin/report/security/db/access.php [new file with mode: 0644]
admin/report/security/index.php [new file with mode: 0644]
admin/report/security/lib.php [new file with mode: 0644]
admin/report/security/settings.php [new file with mode: 0644]
admin/report/security/version.php [new file with mode: 0644]
lang/en_utf8/report_security.php [new file with mode: 0644]
theme/standard/styles_color.css

diff --git a/admin/report/security/db/access.php b/admin/report/security/db/access.php
new file mode 100644 (file)
index 0000000..8534dd8
--- /dev/null
@@ -0,0 +1,36 @@
+<?php  // $Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.com       //
+//                                                                       //
+// 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 2 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:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+$report_security_capabilities = array(
+
+    'report/security:view' => array(
+        'riskbitmask' => RISK_CONFIG,
+        'captype' => 'read',
+        'contextlevel' => CONTEXT_SYSTEM,
+        'legacy' => array(
+            'admin' => CAP_ALLOW
+        ),
+    )
+);
diff --git a/admin/report/security/index.php b/admin/report/security/index.php
new file mode 100644 (file)
index 0000000..19b626f
--- /dev/null
@@ -0,0 +1,113 @@
+<?php  //$Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas  http://dougiamas.com     //
+//                                                                       //
+// 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 2 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:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once('../../../config.php');
+require_once($CFG->dirroot.'/'.$CFG->admin.'/report/security/lib.php');
+require_once($CFG->libdir.'/adminlib.php');
+
+require_login();
+
+$issue = optional_param('issue', '', PARAM_ALPHANUMEXT); // show detailed info about one issue only
+
+$issues = report_security_get_issue_list();
+
+// test if issue valid string
+if (array_search($issue, $issues, true) === false) {
+    $issue = '';
+}
+
+// Print the header.
+admin_externalpage_setup('reportsecurity');
+admin_externalpage_print_header();
+
+print_heading(get_string('reportsecurity', 'report_security'));
+
+$strok       = '<span class="statusok">'.get_string('statusok', 'report_security').'</span>';
+$strinfo     = '<span class="statusinfo">'.get_string('statusinfo', 'report_security').'</span>';
+$strwarning  = '<span class="statuswarning">'.get_string('statuswarning', 'report_security').'</span>';
+$strserious  = '<span class="statusserious">'.get_string('statusserious', 'report_security').'</span>';
+$strcritical = '<span class="statuscritical">'.get_string('statuscritical', 'report_security').'</span>';
+
+$strissue    = get_string('issue', 'report_security');
+$strstatus   = get_string('status', 'report_security');
+$strdesc     = get_string('description', 'report_security');
+$strconfig   = get_string('configuration', 'report_security');
+
+$statusarr = array(REPORT_SECURITY_OK       => $strok,
+                   REPORT_SECURITY_INFO     => $strinfo,
+                   REPORT_SECURITY_WARNING  => $strwarning,
+                   REPORT_SECURITY_SERIOUS  => $strserious,
+                   REPORT_SECURITY_CRITICAL => $strcritical);
+
+$url = "$CFG->wwwroot/$CFG->admin/report/security/index.php";
+
+if ($issue and ($result = $issue(true))) {
+    $table = new object();
+    $table->head  = array($strissue, $strstatus, $strdesc, $strconfig);
+    $table->size  = array('30%', '10%', '50%', '10%' );
+    $table->align = array('left', 'left', 'left', 'left');
+    $table->width = '90%';
+    $table->data  = array();
+
+    // print detail of one issue only
+    $row = array();
+    $row[0] = $result->name;
+    $row[1] = $statusarr[$result->status];
+    $row[2] = $result->info;
+    $row[3] = is_null($result->link) ? '-' : "<a href='$result->link'>$strconfig</a>";
+
+    $table->data[] = $row;
+
+    print_table($table);
+
+    print_box($result->details, 'generalbox boxwidthnormal boxaligncenter'); // TODO: add proper css
+
+    print_continue($url);
+
+} else {
+    $table = new object();
+    $table->head  = array($strissue, $strstatus, $strdesc);
+    $table->size  = array('30%', '10%', '60%' );
+    $table->align = array('left', 'left', 'left');
+    $table->width = '90%';
+    $table->data  = array();
+
+    foreach ($issues as $issue) {
+        $result = $issue(false);
+        if (!$result) {
+            // ignore this test
+            continue;
+        }
+        $row = array();
+        $row[0] = "<a href='$url?issue=$result->issue'>$result->name</a>";
+        $row[1] = $statusarr[$result->status];
+        $row[2] = $result->info;
+
+        $table->data[] = $row;
+    }
+    print_table($table);
+}
+
+print_footer();
\ No newline at end of file
diff --git a/admin/report/security/lib.php b/admin/report/security/lib.php
new file mode 100644 (file)
index 0000000..7cb17c0
--- /dev/null
@@ -0,0 +1,1031 @@
+<?php  //$Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.org                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards Martin Dougiamas  http://dougiamas.com     //
+//                                                                       //
+// 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 2 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:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+require_once("$CFG->libdir/adminlib.php");
+
+
+define('REPORT_SECURITY_OK', 'ok');
+define('REPORT_SECURITY_INFO', 'info');
+define('REPORT_SECURITY_WARNING', 'warning');
+define('REPORT_SECURITY_SERIOUS', 'serious');
+define('REPORT_SECURITY_CRITICAL', 'critical');
+
+
+function report_security_get_issue_list() {
+    return array(
+        'report_security_check_globals',
+        'report_security_check_unsecuredataroot',
+        'report_security_check_displayerrors',
+        'report_security_check_noauth',
+        'report_security_check_embed',
+        'report_security_check_mediafilterswf',
+        'report_security_check_openprofiles',
+        'report_security_check_google',
+        'report_security_check_passwordpolicy',
+        'report_security_check_emailchangeconfirmation',
+        'report_security_check_cookiesecure',
+        'report_security_check_configrw',
+        'report_security_check_riskxss',
+        'report_security_check_riskadmin',
+        'report_security_check_defaultuserrole',
+        'report_security_check_guestrole',
+        'report_security_check_frontpagerole',
+        'report_security_check_defaultcourserole',
+        'report_security_check_courserole',
+
+    );
+}
+
+///=============================================
+///               Issue checks
+///=============================================
+
+
+/**
+ * Verifies register globals PHP setting.
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_globals($detailed=false) {
+    $result = new object();
+    $result->issue   = 'report_security_check_globals';
+    $result->name    = get_string('check_globals_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = null;
+
+    if (ini_get_bool('register_globals')) {
+        $result->status = REPORT_SECURITY_CRITICAL;
+        $result->info   = get_string('check_globals_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_globals_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_globals_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies unsupported noauth setting
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_noauth($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_noauth';
+    $result->name    = get_string('check_noauth_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=manageauths";
+
+    if (is_enabled_auth('none')) {
+        $result->status = REPORT_SECURITY_CRITICAL;
+        $result->info   = get_string('check_noauth_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_noauth_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_noauth_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies if password policy set
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_passwordpolicy($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_passwordpolicy';
+    $result->name    = get_string('check_passwordpolicy_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies";
+
+    if (empty($CFG->passwordpolicy)) {
+        $result->status = REPORT_SECURITY_WARNING;
+        $result->info   = get_string('check_passwordpolicy_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_passwordpolicy_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_passwordpolicy_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies sloppy embedding - this should have been removed long ago!!
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_embed($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_embed';
+    $result->name    = get_string('check_embed_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies";
+
+    if (!empty($CFG->allowobjectembed)) {
+        $result->status = REPORT_SECURITY_CRITICAL;
+        $result->info   = get_string('check_embed_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_embed_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_embed_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies sloppy swf embedding - this should have been removed long ago!!
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_mediafilterswf($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_mediafilterswf';
+    $result->name    = get_string('check_mediafilterswf_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=filtersettingfiltermediaplugin";
+
+    if (!empty($CFG->textfilters)) {
+        $activefilters = explode(',', $CFG->textfilters);
+    } else {
+        $activefilters = array();
+    }
+
+    if (array_search('filter/mediaplugin', $activefilters) !== false and !empty($CFG->filter_mediaplugin_enable_swf)) {
+        $result->status = REPORT_SECURITY_CRITICAL;
+        $result->info   = get_string('check_mediafilterswf_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_mediafilterswf_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_mediafilterswf_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies fatal misconfiguration of dataroot
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_unsecuredataroot($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_unsecuredataroot';
+    $result->name    = get_string('check_unsecuredataroot_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = null;
+
+    $insecuredataroot = is_dataroot_insecure(true);
+
+    if ($insecuredataroot == INSECURE_DATAROOT_WARNING) {
+        $result->status = REPORT_SECURITY_SERIOUS;
+        $result->info   = get_string('check_unsecuredataroot_warning', 'report_security', $CFG->dataroot);
+
+    } else if ($insecuredataroot == INSECURE_DATAROOT_ERROR) {
+        $result->status = REPORT_SECURITY_CRITICAL;
+        $result->info   = get_string('check_unsecuredataroot_error', 'report_security', $CFG->dataroot);
+
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_unsecuredataroot_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_unsecuredataroot_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies disaplying of errors - problem for lib files and 3rd party code
+ * because we can not disable debugging in these scripts (they do not include config.php)
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_displayerrors($detailed=false) {
+    $result = new object();
+    $result->issue   = 'report_security_check_displayerrors';
+    $result->name    = get_string('check_displayerrors_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = null;
+
+    if (defined('WARN_DISPLAY_ERRORS_ENABLED')) {
+        $result->status = REPORT_SECURITY_WARNING;
+        $result->info   = get_string('check_displayerrors_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_displayerrors_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_displayerrors_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies open profiles - originaly open by default, not anymore because spammer abused it a lot
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_openprofiles($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_openprofiles';
+    $result->name    = get_string('check_openprofiles_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies";
+
+    if (empty($CFG->forcelogin) and empty($CFG->forceloginforprofiles)) {
+        $result->status = REPORT_SECURITY_WARNING;
+        $result->info   = get_string('check_openprofiles_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_openprofiles_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_openprofiles_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies google access not combined with disabled guest access
+ * because attackers might gain guest access by modifying browser signature.
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_google($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_google';
+    $result->name    = get_string('check_google_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies";
+
+    if (empty($CFG->opentogoogle)) {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_google_ok', 'report_security');
+    } else if (!empty($CFG->guestloginbutton)) {
+        $result->status = REPORT_SECURITY_INFO;
+        $result->info   = get_string('check_google_info', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_SERIOUS;
+        $result->info   = get_string('check_google_error', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_google_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies email confirmation - spammers were changing mails very often
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_emailchangeconfirmation($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_emailchangeconfirmation';
+    $result->name    = get_string('check_emailchangeconfirmation_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies";
+
+    if (empty($CFG->emailchangeconfirmation)) {
+        $result->status = REPORT_SECURITY_WARNING;
+        $result->info   = get_string('check_emailchangeconfirmation_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_emailchangeconfirmation_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_emailchangeconfirmation_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies if https enabled only secure cookies allowed,
+ * this prevents redirections and sending of cookies to unsecure port.
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_cookiesecure($detailed=false) {
+    global $CFG;
+
+    if (strpos($CFG->wwwroot, 'https://') !== 0) {
+        return null;
+    }
+
+    $result = new object();
+    $result->issue   = 'report_security_check_cookiesecure';
+    $result->name    = get_string('check_cookiesecure_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=httpsecurity";
+
+    if (empty($CFG->cookiesecure)) {
+        $result->status = REPORT_SECURITY_SERIOUS;
+        $result->info   = get_string('check_cookiesecure_error', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_cookiesecure_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_cookiesecure_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies config.php is not writable anymore after installation,
+ * config files were changed on several outdated server.
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_configrw($detailed=false) {
+    global $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_configrw';
+    $result->name    = get_string('check_configrw_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = null;
+
+    if (is_writable($CFG->dirroot.'/config.php')) {
+        $result->status = REPORT_SECURITY_WARNING;
+        $result->info   = get_string('check_configrw_warning', 'report_security');
+    } else {
+        $result->status = REPORT_SECURITY_OK;
+        $result->info   = get_string('check_configrw_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_configrw_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 :-(
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_riskxss($detailed=false) {
+    global $DB;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_riskxss';
+    $result->name    = get_string('check_riskxss_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = REPORT_SECURITY_WARNING;
+    $result->link    = null;
+
+    $params = array('capallow'=>CAP_ALLOW);
+
+    $sqlfrom = "FROM {role_capabilities} rc
+                JOIN {capabilities} cap ON cap.name = rc.capability
+                JOIN {context} c ON c.id = rc.contextid
+                JOIN {context} sc ON (sc.path = c.path OR sc.path LIKE ".$DB->sql_concat('c.path', "'/%'").")
+                JOIN {role_assignments} ra ON (ra.contextid = sc.id AND ra.roleid = rc.roleid)
+                JOIN {user} u ON u.id = ra.userid
+               WHERE ".$DB->sql_bitand('cap.riskbitmask', RISK_XSS)."
+                     AND rc.permission = :capallow
+                     AND u.deleted = 0";
+
+    $count = $DB->count_records_sql("SELECT COUNT(DISTINCT u.id) $sqlfrom", $params);
+
+    $result->info = get_string('check_riskxss_warning', 'report_security', $count);
+
+    if ($detailed) {
+        $users = $DB->get_records_sql("SELECT DISTINCT u.id, u.firstname, u.lastname, u.picture, u.imagealt $sqlfrom", $params);
+        foreach ($users as $uid=>$user) {
+            $users[$uid] = fullname($user);
+        }
+        $users = implode(', ', $users);
+        $result->details = get_string('check_riskxss_details', 'report_security', $users);
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies sanity of default user role.
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_defaultuserrole($detailed=false) {
+    global $DB, $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_defaultuserrole';
+    $result->name    = get_string('check_defaultuserrole_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies";
+
+    if (!$default_role = $DB->get_record('role', array('id'=>$CFG->defaultuserroleid))) {
+        $result->status  = REPORT_SECURITY_WARNING;
+        $result->info    = get_string('check_defaultuserrole_notset', 'report_security');
+        $result->details = $result->info;
+
+        return $result;
+    }
+
+    // first test if do anything enabled - that would be really crazy!
+    $params = array('doanything'=>'moodle/site:doanything', 'capallow'=>CAP_ALLOW, 'roleid'=>$default_role->id);
+    $sql = "SELECT COUNT(DISTINCT rc.contextid)
+              FROM {role_capabilities} rc
+             WHERE rc.capability = :doanything
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+
+    $anythingcount = $DB->count_records_sql($sql, $params);
+
+    // risky caps - usually very dangerous
+    $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$default_role->id);
+    $sql = "SELECT COUNT(DISTINCT rc.contextid)
+              FROM {role_capabilities} rc
+              JOIN {capabilities} cap ON cap.name = rc.capability
+             WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))."
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+
+    $riskycount = $DB->count_records_sql($sql, $params);
+
+    // default role can not have view cap in all courses - this would break moodle badly
+    $viewcap = $DB->record_exists('role_capabilities', array('roleid'=>$default_role->id, 'permission'=>CAP_ALLOW, 'capability'=>'moodle/course:view'));
+
+    // it may have either no or 'user' legacy type - nothing else, or else it would break during upgrades badly
+    $legacyok = false;
+    $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$default_role->id, 'legacy'=>'moodle/legacy:%');
+    $sql = "SELECT rc.capability, 1
+              FROM {role_capabilities} rc
+             WHERE rc.capability LIKE :legacy
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+    $legacycaps = $DB->get_records_sql($sql, $params);
+    if (!$legacycaps) {
+        $legacyok = true;
+    } else if (count($legacycaps) == 1 and isset($legacycaps['moodle/legacy:user'])) {
+        $legacyok = true;
+    }
+
+    if ($anythingcount or $riskycount or $viewcap or !$legacyok) {
+        $result->status  = REPORT_SECURITY_CRITICAL;
+        $result->info    = get_string('check_defaultuserrole_error', 'report_security', format_string($default_role->name));
+
+    } else {
+        $result->status  = REPORT_SECURITY_OK;
+        $result->info    = get_string('check_defaultuserrole_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_defaultuserrole_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies sanity of guest role
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_guestrole($detailed=false) {
+    global $DB, $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_guestrole';
+    $result->name    = get_string('check_guestrole_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies";
+
+    if (!$guest_role = $DB->get_record('role', array('id'=>$CFG->guestroleid))) {
+        $result->status  = REPORT_SECURITY_WARNING;
+        $result->info    = get_string('check_guestrole_notset', 'report_security');
+        $result->details = $result->info;
+
+        return $result;
+    }
+
+    // first test if do anything enabled - that would be really crazy!
+    $params = array('doanything'=>'moodle/site:doanything', 'capallow'=>CAP_ALLOW, 'roleid'=>$guest_role->id);
+    $sql = "SELECT COUNT(DISTINCT rc.contextid)
+              FROM {role_capabilities} rc
+             WHERE rc.capability = :doanything
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+
+    $anythingcount = $DB->count_records_sql($sql, $params);
+
+    // risky caps - usually very dangerous
+    $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$guest_role->id);
+    $sql = "SELECT COUNT(DISTINCT rc.contextid)
+              FROM {role_capabilities} rc
+              JOIN {capabilities} cap ON cap.name = rc.capability
+             WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))."
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+
+    $riskycount = $DB->count_records_sql($sql, $params);
+
+    // it may have either no or 'guest' legacy type - nothing else, or else it would break during upgrades badly
+    $legacyok = false;
+    $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$guest_role->id, 'legacy'=>'moodle/legacy:%');
+    $sql = "SELECT rc.capability, 1
+              FROM {role_capabilities} rc
+             WHERE rc.capability LIKE :legacy
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+    $legacycaps = $DB->get_records_sql($sql, $params);
+    if (!$legacycaps) {
+        $legacyok = true;
+    } else if (count($legacycaps) == 1 and isset($legacycaps['moodle/legacy:guest'])) {
+        $legacyok = true;
+    }
+
+    if ($anythingcount or $riskycount or !$legacyok) {
+        $result->status  = REPORT_SECURITY_CRITICAL;
+        $result->info    = get_string('check_guestrole_error', 'report_security', format_string($guest_role->name));
+
+    } else {
+        $result->status  = REPORT_SECURITY_OK;
+        $result->info    = get_string('check_guestrole_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_guestrole_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies sanity of frontpage role
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_frontpagerole($detailed=false) {
+    global $DB, $CFG;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_frontpagerole';
+    $result->name    = get_string('check_frontpagerole_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=frontpagesettings";
+
+    if (!$frontpage_role = $DB->get_record('role', array('id'=>$CFG->defaultfrontpageroleid))) {
+        $result->status  = REPORT_SECURITY_INFO;
+        $result->info    = get_string('check_frontpagerole_notset', 'report_security');
+        $result->details = get_string('check_frontpagerole_details', 'report_security');
+
+        return $result;
+    }
+
+    // first test if do anything enabled - that would be really crazy!
+    $params = array('doanything'=>'moodle/site:doanything', 'capallow'=>CAP_ALLOW, 'roleid'=>$frontpage_role->id);
+    $sql = "SELECT COUNT(DISTINCT rc.contextid)
+              FROM {role_capabilities} rc
+             WHERE rc.capability = :doanything
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+
+    $anythingcount = $DB->count_records_sql($sql, $params);
+
+    // risky caps - usually very dangerous
+    $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$frontpage_role->id);
+    $sql = "SELECT COUNT(DISTINCT rc.contextid)
+              FROM {role_capabilities} rc
+              JOIN {capabilities} cap ON cap.name = rc.capability
+             WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))."
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+
+    $riskycount = $DB->count_records_sql($sql, $params);
+
+    // there is no legacy role type for frontpage yet - anyway we can not allow teachers or admins there!
+    $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$frontpage_role->id, 'legacy'=>'moodle/legacy:%');
+    $sql = "SELECT rc.capability, 1
+              FROM {role_capabilities} rc
+             WHERE rc.capability LIKE :legacy
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+    $legacycaps = $DB->get_records_sql($sql, $params);
+    $legacyok = (!isset($legacycaps['moodle/legacy:teacher'])
+                 and !isset($legacycaps['moodle/legacy:editingteacher'])
+                 and !isset($legacycaps['moodle/legacy:coursecreator'])
+                 and !isset($legacycaps['moodle/legacy:admin']));
+
+    if ($anythingcount or $riskycount or !$legacyok) {
+        $result->status  = REPORT_SECURITY_CRITICAL;
+        $result->info    = get_string('check_frontpagerole_error', 'report_security', format_string($frontpage_role->name));
+
+    } else {
+        $result->status  = REPORT_SECURITY_OK;
+        $result->info    = get_string('check_frontpagerole_ok', 'report_security');
+    }
+
+    if ($detailed) {
+        $result->details = get_string('check_frontpagerole_details', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies sanity of site default course role.
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_defaultcourserole($detailed=false) {
+    global $DB, $CFG;
+
+    $problems = array();
+
+    $result = new object();
+    $result->issue   = 'report_security_check_defaultcourserole';
+    $result->name    = get_string('check_defaultcourserole_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = "$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies";
+
+    if ($detailed) {
+        $result->details = get_string('check_defaultcourserole_details', 'report_security');
+    }
+
+    if (!$student_role = $DB->get_record('role', array('id'=>$CFG->defaultcourseroleid))) {
+        $result->status  = REPORT_SECURITY_WARNING;
+        $result->info    = get_string('check_defaultcourserole_notset', 'report_security');
+        $result->details = get_string('check_defaultcourserole_details', 'report_security');
+
+        return $result;
+    }
+
+    // first test if do anything enabled - that would be really crazy!
+    $params = array('doanything'=>'moodle/site:doanything', 'capallow'=>CAP_ALLOW, 'roleid'=>$student_role->id);
+    $sql = "SELECT DISTINCT rc.contextid
+              FROM {role_capabilities} rc
+             WHERE rc.capability = :doanything
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+
+    if ($anything_contexts = $DB->get_records_sql($sql, $params)) {
+        foreach($anything_contexts as $contextid) {
+            if ($contextid == SYSCONTEXTID) {
+                $a = "$CFG->wwwroot/$CFG->admin/roles/define.php?action=view&roleid=$CFG->defaultcourseroleid";
+            } else {
+                $a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$CFG->defaultcourseroleid";
+            }
+            $problems[] = get_string('check_defaultcourserole_anything', 'report_security', $a);
+        }
+    }
+
+    // risky caps - usually very dangerous
+    $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$student_role->id);
+    $sql = "SELECT DISTINCT rc.contextid
+              FROM {role_capabilities} rc
+              JOIN {capabilities} cap ON cap.name = rc.capability
+             WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))."
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+
+    if ($riskycontexts = $DB->get_records_sql($sql, $params)) {
+        foreach($riskycontexts as $contextid=>$unused) {
+            if ($contextid == SYSCONTEXTID) {
+                $a = "$CFG->wwwroot/$CFG->admin/roles/define.php?action=view&roleid=$CFG->defaultcourseroleid";
+            } else {
+                $a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$CFG->defaultcourseroleid";
+            }
+            $problems[] = get_string('check_defaultcourserole_risky', 'report_security', $a);
+        }
+    }
+
+    // course creator or administrator does not make any sense here
+    $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$student_role->id, 'legacy'=>'moodle/legacy:%');
+    $sql = "SELECT rc.capability, 1
+              FROM {role_capabilities} rc
+             WHERE rc.capability LIKE :legacy
+                   AND rc.permission = :capallow
+                   AND rc.roleid = :roleid";
+    $legacycaps = $DB->get_records_sql($sql, $params);
+    if (isset($legacycaps['moodle/legacy:coursecreator']) or isset($legacycaps['moodle/legacy:admin'])) {
+        $problems[] = get_string('check_defaultcourserole_legacy', 'report_security');
+    }
+
+    if ($problems) {
+        $result->status  = REPORT_SECURITY_CRITICAL;
+        $result->info    = get_string('check_defaultcourserole_error', 'report_security', format_string($student_role->name));
+        if ($detailed) {
+            $result->details .= "<ul>";
+            foreach ($problems as $problem) {
+                $result->details .= "<li>$problem</li>";
+            }
+            $result->details .= "</ul>";
+        }
+
+    } else {
+        $result->status  = REPORT_SECURITY_OK;
+        $result->info    = get_string('check_defaultcourserole_ok', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Verifies sanity of default roles in courses.
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_courserole($detailed=false) {
+    global $DB, $CFG, $SITE;
+
+    $problems = array();
+
+    $result = new object();
+    $result->issue   = 'report_security_check_courserole';
+    $result->name    = get_string('check_courserole_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = null;
+
+    if ($detailed) {
+        $result->details = get_string('check_courserole_details', 'report_security');
+    }
+
+    // get list of all student roles selected in courses excluding the default course role
+    $params = array('siteid'=>$SITE->id, 'defaultcourserole'=>$CFG->defaultcourseroleid);
+    $sql = "SELECT r.*
+              FROM {role} r
+              JOIN {course} c ON c.defaultrole = r.id
+             WHERE c.id <> :siteid AND r.id <> :defaultcourserole";
+
+    if (!$student_roles = $DB->get_records_sql($sql, $params)) {
+        $result->status  = REPORT_SECURITY_OK;
+        $result->info    = get_string('check_courserole_notyet', 'report_security');
+        $result->details = get_string('check_courserole_details', 'report_security');
+
+        return $result;
+    }
+
+    $roleids = array_keys($student_roles);
+
+    // first test if do anything enabled - that would be really crazy!!!!!!
+    list($inroles, $params) = $DB->get_in_or_equal($roleids, SQL_PARAMS_NAMED, 'r0', true);
+    $params = array_merge($params, array('doanything'=>'moodle/site:doanything', 'capallow'=>CAP_ALLOW));
+    $params['doanything'] = 'moodle/site:doanything';
+    $params['capallow']   = CAP_ALLOW;
+    $sql = "SELECT rc.roleid, rc.contextid
+              FROM {role_capabilities} rc
+             WHERE rc.capability = :doanything
+                   AND rc.permission = :capallow
+                   AND rc.roleid $inroles
+          GROUP BY rc.roleid, rc.contextid
+          ORDER BY rc.roleid, rc.contextid";
+
+    $rs = $DB->get_recordset_sql($sql, $params);
+    foreach($rs as $res) {
+        $roleid    = $res->roleid;
+        $contextid = $res->contextid;
+        if ($contextid == SYSCONTEXTID) {
+            $a = "$CFG->wwwroot/$CFG->admin/roles/define.php?action=view&roleid=$roleid";
+        } else {
+            $a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$roleid";
+        }
+        $problems[] = get_string('check_courserole_anything', 'report_security', $a);
+    }
+    $rs->close();
+
+    // risky caps in any level - usually very dangerous!!
+    list($inroles, $params) = $DB->get_in_or_equal($roleids, SQL_PARAMS_NAMED, 'r0', true);
+    $params = array_merge($params, array('capallow'=>CAP_ALLOW));
+    $sql = "SELECT rc.roleid, rc.contextid
+              FROM {role_capabilities} rc
+              JOIN {capabilities} cap ON cap.name = rc.capability
+             WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))."
+                   AND rc.permission = :capallow
+                   AND rc.roleid $inroles
+          GROUP BY rc.roleid, rc.contextid
+          ORDER BY rc.roleid, rc.contextid";
+    $rs = $DB->get_recordset_sql($sql, $params);
+    foreach($rs as $res) {
+        $roleid    = $res->roleid;
+        $contextid = $res->contextid;
+        if ($contextid == SYSCONTEXTID) {
+            $a = "$CFG->wwwroot/$CFG->admin/roles/define.php?action=view&roleid=$roleid";
+        } else {
+            $a = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$contextid&roleid=$roleid";
+        }
+        $problems[] = get_string('check_courserole_risky', 'report_security', $a);
+    }
+    $rs->close();
+
+    // course creator or administrator does not make any sense here!
+    list($inroles, $params) = $DB->get_in_or_equal($roleids, SQL_PARAMS_NAMED, 'r0', true);
+    $params = array_merge($params, array('capallow'=>CAP_ALLOW, 'creator'=>'moodle/legacy:coursecreator', 'admin'=>'moodle/legacy:admin'));
+    $sql = "SELECT DISTINCT rc.roleid
+              FROM {role_capabilities} rc
+             WHERE (rc.capability = :creator OR rc.capability = :admin)
+                   AND rc.permission = :capallow
+                   AND rc.roleid $inroles";
+    if ($legacys = $DB->get_records_sql($sql, $params)) {
+        foreach ($legacys as $roleid=>$unused) {
+            $a = "$CFG->wwwroot/$CFG->admin/roles/define.php?action=view&roleid=$roleid";
+            $problems[] = get_string('check_defaultcourserole_legacy', 'report_security', $a);
+        }
+    }
+
+
+    if ($problems) {
+        $result->status  = REPORT_SECURITY_CRITICAL;
+        $result->info    = get_string('check_courserole_error', 'report_security');
+        if ($detailed) {
+            $result->details .= "<ul>";
+            foreach ($problems as $problem) {
+                $result->details .= "<li>$problem</li>";
+            }
+            $result->details .= "</ul>";
+        }
+
+    } else {
+        $result->status  = REPORT_SECURITY_OK;
+        $result->info    = get_string('check_courserole_ok', 'report_security');
+    }
+
+    return $result;
+}
+
+/**
+ * Lists all admins.
+ * @param bool $detailed
+ * @return object result
+ */
+function report_security_check_riskadmin($detailed=false) {
+    global $DB;
+
+    $result = new object();
+    $result->issue   = 'report_security_check_riskadmin';
+    $result->name    = get_string('check_riskadmin_name', 'report_security');
+    $result->info    = null;
+    $result->details = null;
+    $result->status  = null;
+    $result->link    = null;
+
+    $params = array('doanything'=>'moodle/site:doanything', 'syscontextid'=>SYSCONTEXTID, 'capallow'=>CAP_ALLOW);
+
+    $sql = "SELECT DISTINCT u.id, u.firstname, u.lastname, u.picture, u.imagealt
+              FROM {role_capabilities} rc
+              JOIN {role_assignments} ra ON (ra.contextid = rc.contextid AND ra.roleid = rc.roleid)
+              JOIN {user} u ON u.id = ra.userid
+             WHERE rc.capability = :doanything
+                   AND rc.permission = :capallow
+                   AND u.deleted = 0
+                   AND rc.contextid = :syscontextid";
+
+    $admins = $DB->get_records_sql($sql, $params);
+
+    $sqlfrom = "FROM {role_capabilities} rc
+                JOIN {context} c ON c.id = rc.contextid
+                JOIN {context} sc ON (sc.path = c.path OR sc.path LIKE ".$DB->sql_concat('c.path', "'/%'").")
+                JOIN {role_assignments} ra ON (ra.contextid = sc.id AND ra.roleid = rc.roleid)
+                JOIN {user} u ON u.id = ra.userid
+               WHERE rc.capability = :doanything
+                     AND rc.permission = :capallow
+                     AND u.deleted = 0
+                     AND ra.contextid <> :syscontextid";
+
+    $count = $DB->count_records_sql("SELECT COUNT(DISTINCT u.id) $sqlfrom", $params);
+
+    if (!$count) {
+        $result->status  = REPORT_SECURITY_OK;
+        $result->info = get_string('check_riskadmin_ok', 'report_security', count($admins));
+
+        if ($detailed) {
+            foreach ($admins as $uid=>$user) {
+                $admins[$uid] = fullname($user);
+            }
+            $admins = implode(', ', $admins);
+            $result->details = get_string('check_riskadmin_detailsok', 'report_security', $admins);
+        }
+
+    } else {
+        $result->status  = REPORT_SECURITY_WARNING;
+        $a = (object)array('admincount'=>count($admins), 'unsupcount'=>$count);
+        $result->info = get_string('check_riskadmin_warning', 'report_security', $a);
+
+        if ($detailed) {
+            foreach ($admins as $uid=>$user) {
+                $admins[$uid] = fullname($user);
+            }
+            $admins = implode(', ', $admins);
+            $users = $DB->get_records_sql("SELECT DISTINCT u.id, u.firstname, u.lastname, u.picture, u.imagealt $sqlfrom", $params);
+            foreach ($users as $uid=>$user) {
+                $users[$uid] = fullname($user);
+            }
+            $users = implode(', ', $users);
+            $a = (object)array('admins'=>$admins, 'unsupported'=>$users);
+            $result->details = get_string('check_riskadmin_detailswarning', 'report_security', $a);
+        }
+    }
+
+    return $result;
+}
diff --git a/admin/report/security/settings.php b/admin/report/security/settings.php
new file mode 100644 (file)
index 0000000..71bf148
--- /dev/null
@@ -0,0 +1,3 @@
+<?php  //$Id$
+
+$ADMIN->add('reports', new admin_externalpage('reportsecurity', get_string('reportsecurity', 'report_security'), "$CFG->wwwroot/$CFG->admin/report/security/index.php",'report/security:view'));
diff --git a/admin/report/security/version.php b/admin/report/security/version.php
new file mode 100644 (file)
index 0000000..181e9af
--- /dev/null
@@ -0,0 +1,29 @@
+<?PHP // $Id$
+
+///////////////////////////////////////////////////////////////////////////
+//                                                                       //
+// NOTICE OF COPYRIGHT                                                   //
+//                                                                       //
+// Moodle - Modular Object-Oriented Dynamic Learning Environment         //
+//          http://moodle.com                                            //
+//                                                                       //
+// Copyright (C) 1999 onwards  Martin Dougiamas  http://moodle.com       //
+//                                                                       //
+// 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 2 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:                          //
+//                                                                       //
+//          http://www.gnu.org/copyleft/gpl.html                         //
+//                                                                       //
+///////////////////////////////////////////////////////////////////////////
+
+$plugin->version  = 2008122900;
+$plugin->requires = 2008121701;
+
+?>
diff --git a/lang/en_utf8/report_security.php b/lang/en_utf8/report_security.php
new file mode 100644 (file)
index 0000000..b853ecc
--- /dev/null
@@ -0,0 +1,138 @@
+<?PHP  // $Id$
+
+
+//NOTE TO TRANSLATORS: please do not translate yet, we are going to finalise this file sometime in January and backport to 1.9.x ;-)
+
+$string['configuration'] = 'Configuration';
+$string['details'] = 'Details';
+$string['description'] = 'Description';
+$string['issue'] = 'Issue';
+$string['reportsecurity'] = 'Security overview';
+$string['security:view'] = 'View security report';
+$string['status'] = 'Status';
+$string['statuscritical'] = 'Critical';
+$string['statusinfo'] = 'Information';
+$string['statusok'] = 'OK';
+$string['statusserious'] = 'Serious';
+$string['statuswarning'] = 'Warning';
+
+$string['check_configrw_details'] = '<p>It is recommended to change file permissions of config.php script after installation so that the file can not be modified by web server.
+Please note that this measure does not improve security of the server significantly, but on the other hand it might slow down or limit general exploits.</p>';
+$string['check_configrw_name'] = 'Writable config.php';
+$string['check_configrw_ok'] = 'config.php can not be modified by PHP scripts.';
+$string['check_configrw_warning'] = 'PHP scripts may modify config.php.';
+
+$string['check_cookiesecure_details'] = '<p>If you enable https communication it is recommended to enable secure cookies. You should also add permanent redirection from http to https.</p>';
+$string['check_cookiesecure_error'] = 'Please enable secure cookies';
+$string['check_cookiesecure_name'] = 'Secure cookies';
+$string['check_cookiesecure_ok'] = 'Secure cookies enabled.';
+
+$string['check_courserole_anything'] = 'Do anything capability must not be allowed in this <a href=\"$a\">context</a>.';
+$string['check_courserole_details'] = '<p>Each course has one default enrolment role specified. Please make sure no risky capabilities are allowed in this role.</p>
+<p>The only supported legacy type for course default role is <em>Student</em>.</p>';
+$string['check_courserole_error'] = 'Incorrectly defined course default roles detected!';
+$string['check_courserole_legacy'] = 'Unsupported legacy type detected in <a href=\"$a\">role</a>.';
+$string['check_courserole_name'] = 'Course default roles';
+$string['check_courserole_notyet'] = 'Used only default course role.';
+$string['check_courserole_ok'] = 'Course default role definitions ok.';
+$string['check_courserole_risky'] = 'Risky capabilities detected in <a href=\"$a\">context</a>.';
+
+$string['check_defaultcourserole_anything'] = 'Do anything capability must not be allowed in this <a href=\"$a\">context</a>.';
+$string['check_defaultcourserole_details'] = '<p>Default student role for course enrolment specifies the default role for courses. Please make sure no risky capabilities are allowed in this role.</p>
+<p>The only supported legacy type for default role is <em>Student</em>.</p>';
+$string['check_defaultcourserole_error'] = 'Incorrectly defined default course role \"$a\" detected!';
+$string['check_defaultcourserole_legacy'] = 'Unsupported legacy type detected.';
+$string['check_defaultcourserole_name'] = 'Site default course role';
+$string['check_defaultcourserole_notset'] = 'Default role is not set.';
+$string['check_defaultcourserole_ok'] = 'Site default role definition ok.';
+$string['check_defaultcourserole_risky'] = 'Risky capabilities detected in <a href=\"$a\">context</a>.';
+
+$string['check_defaultuserrole_details'] = '<p>All logged in users are given capabilities of the default user role. Please make sure no risky capabilities are allowed in this role.</p>
+<p>The only supported legacy type for default user role is <em>Authenticated user</em>. Course view capability must not be enabled.</p>';
+$string['check_defaultuserrole_error'] = 'Incorrectly defined default user role \"$a\" detected!';
+$string['check_defaultuserrole_name'] = 'Registered user role';
+$string['check_defaultuserrole_notset'] = 'Default role is not set.';
+$string['check_defaultuserrole_ok'] = 'Registered user role definition ok.';
+
+$string['check_displayerrors_details'] = '<p>Enabling the PHP setting <code>display_errors</code> is not recommended on production sites because some error messages may reveal sensitive information about your server.</p>';
+$string['check_displayerrors_error'] = 'PHP errors displaying is enabled. It is recommended to disable displaying of errors in PHP configuration.';
+$string['check_displayerrors_name'] = 'Displaying of PHP errors';
+$string['check_displayerrors_ok'] = 'Displaying of PHP errors disabled.';
+
+$string['check_emailchangeconfirmation_details'] = '<p>It is recommended to require email confirmation step when user enters a new email address in user profile. If disabled spammers might try to exploit server for resending of spam.</p>';
+$string['check_emailchangeconfirmation_error'] = 'Users may enter any email address.';
+$string['check_emailchangeconfirmation_name'] = 'Email change confirmation';
+$string['check_emailchangeconfirmation_ok'] = 'Changing of email must be confirmed.';
+
+$string['check_embed_details'] = '<p>Unlimited object embedding is very dangerous - any registered user may launch XSS attack against other server users. Please disable it on production servers.</p>';
+$string['check_embed_error'] = 'Unlimited object embedding enabled - this is very dangerous for majority of servers.';
+$string['check_embed_name'] = 'Allow EMBED and OBJECT';
+$string['check_embed_ok'] = 'Unlimited object embedding not allowed.';
+
+$string['check_frontpagerole_details'] = '<p>Frontpage role is give to all registered users on frontpage. Please make sure no risky capabilities are allowed in this role.</p>
+<p>It is recommended to create a special role only for this purpose and not set any legacy type.</p>';
+$string['check_frontpagerole_error'] = 'Incorrectly defined frontpage role \"$a\" detected!';
+$string['check_frontpagerole_name'] = 'Frontpage role';
+$string['check_frontpagerole_notset'] = 'Frontpage role is not set.';
+$string['check_frontpagerole_ok'] = 'Frontpage role definition ok.';
+
+$string['check_globals_details'] = '<p>Register globals is considered to be a highly insecure PHP setting, there is no reason why it should be enabled. Moodle is not compatible with register globals.</p>
+<p><code>register_globals=off</code> must be set in PHP configuration. This setting is controlled by editing your <code>php.ini</code>, Apache/IIS configuration or <code>.htaccess</code> file.</p>';
+$string['check_globals_error'] = 'Register globals MUST be disabled. Please fix server PHP settings immediately!';
+$string['check_globals_name'] = 'Register globals';
+$string['check_globals_ok'] = 'Register globals are disabled.';
+
+$string['check_google_details'] = '<p>Open to Google settings helps search engines enter courses with guest access. Please note this settings is not expected to be enabled if guest login not allowed.</p>';
+$string['check_google_error'] = 'Search engines guest access allowed and guest access disabled.';
+$string['check_google_info'] = 'Search engines may enter as guests.';
+$string['check_google_name'] = 'Open to Google';
+$string['check_google_ok'] = 'Search engines guest access not enabled.';
+
+$string['check_guestrole_details'] = '<p>Guest role is used for guests, not logged in users and temporary guest course access. Please make sure no risky capabilities are allowed in this role.</p>
+<p>The only supported legacy type for guest role is <em>Guest</em>.</p>';
+$string['check_guestrole_error'] = 'Incorrectly defined guest role \"$a\" detected!';
+$string['check_guestrole_name'] = 'Guest role';
+$string['check_guestrole_notset'] = 'Guest role is not set.';
+$string['check_guestrole_ok'] = 'Guest role definition ok.';
+
+$string['check_mediafilterswf_details'] = '<p>Automatic swf embedding is very dangerous - any registered user may launch XSS attack against other server users. Please disable it on production servers.</p>';
+$string['check_mediafilterswf_error'] = 'Flash media filter is enabled - this is very dangerous for majority of servers.';
+$string['check_mediafilterswf_name'] = 'Enabled .swf media filter';
+$string['check_mediafilterswf_ok'] = 'Flash media filter is not enabled.';
+
+$string['check_noauth_details'] = '<p><em>No authentication</em> plugin is not intended for any production sites. Please disable it unless this is a development test site.</p>';
+$string['check_noauth_error'] = 'No authentication pluing can not be used on production sites.';
+$string['check_noauth_name'] = 'No authentication';
+$string['check_noauth_ok'] = 'No authentication plugin is disabled.';
+
+$string['check_openprofiles_details'] = '<p>Open user profiles are often abused by spammers, it is usually recommended to enable <code>Force users to login for profiles</code> or <code>Force users to login</code> if you require login before any access.</p>';
+$string['check_openprofiles_error'] = 'Anybody may view user profiles without logging in.';
+$string['check_openprofiles_name'] = 'Open user profiles';
+$string['check_openprofiles_ok'] = 'Login is required before viewing user profile.';
+
+$string['check_passwordpolicy_details'] = '<p>It is recommended to enforce user password policy because password guessing is very often the easiest way to gain unauthorised access.
+Do not make the requirements too strict, because users would not be able to remember their passwords and would keep forgetting them or write them down.</p>';
+$string['check_passwordpolicy_error'] = 'Password policy not set.';
+$string['check_passwordpolicy_name'] = 'Password policy';
+$string['check_passwordpolicy_ok'] = 'Password policy enabled.';
+
+$string['check_riskadmin_detailsok'] = '<p>Please verify following list of administrators.<br />$a</p>';
+$string['check_riskadmin_detailswarning'] = '<p>Please verify following list of administrators:<br />$a->admins</p>
+<p>It is recommended to assign administrator role in system context only. Following users have unsuported admin role assignments:<br />$a->unsupported</p>';
+$string['check_riskadmin_name'] = 'Administrators';
+$string['check_riskadmin_ok'] = 'Found $a server administrators.';
+$string['check_riskadmin_warning'] = 'Found $a->admincount server administrators and $a->unsupcount unsuported admin role assignments.';
+
+$string['check_riskxss_details'] = '<p>RISK_XSS marks all dangerous capabilities that only trusted users may use.</p>
+<p>Please verify following list of users and make sure that you trust them completely on this server:<br />$a</p>';
+$string['check_riskxss_name'] = 'XSS trusted users';
+$string['check_riskxss_warning'] = 'RISK_XSS - found $a users that have to be trusted.';
+
+$string['check_unsecuredataroot_details'] = '<p>Dataroot directory must not be accessible via web. The best way to make sure the directory is not accessible is to use directory outside of public web directory.</p>
+<p>If you move the directory you need to update <code>\$CFG->dataroot</code> setting in <code>config.php</code> accordingly.</p>';
+$string['check_unsecuredataroot_error'] = 'Your dataroot directory <code>$a</code> is in the wrong location and is exposed to the web!';
+$string['check_unsecuredataroot_name'] = 'Unsecure dataroot';
+$string['check_unsecuredataroot_ok'] = 'Dataroot directory must not be accessible via web.';
+$string['check_unsecuredataroot_warning'] = 'Your dataroot directory <code>$a</code> is in the wrong location and might be exposed to the web.';
+
+?>
index f464a9205a821e393b37dc224b37066353d7fed7..d5115443f974f89d5585ad8082319ec39d18221c 100644 (file)
@@ -322,6 +322,17 @@ table.flexible .r1 {
   background-color: green;
 }
 
+#admin-report-security-index .statuswarning {
+  background-color: #f0e000;
+}
+
+#admin-report-security-index .statusserious {
+  background-color: #f07000;
+}
+
+#admin-report-security-index .statuscritical {
+  background-color: #f00000;
+}
 
 .plugincompattable td.ok {
     color: #008000;