MDL-57316 media: Setup media plugins in media_manager::instance()
[moodle.git] / report / security / locallib.php
blobf8fe3531470732fdcd923c2446a8f011294d86e8
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Lib functions
20 * @package report
21 * @subpackage security
22 * @copyright 2008 petr Skoda
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
26 defined('MOODLE_INTERNAL') || die;
29 define('REPORT_SECURITY_OK', 'ok');
30 define('REPORT_SECURITY_INFO', 'info');
31 define('REPORT_SECURITY_WARNING', 'warning');
32 define('REPORT_SECURITY_SERIOUS', 'serious');
33 define('REPORT_SECURITY_CRITICAL', 'critical');
35 function report_security_hide_timearning() {
36 global $PAGE;
37 $PAGE->requires->js_init_code("Y.one('#timewarning').addClass('timewarninghidden')");
40 function report_security_get_issue_list() {
41 return array(
42 'report_security_check_unsecuredataroot',
43 'report_security_check_displayerrors',
44 'report_security_check_noauth',
45 'report_security_check_embed',
46 'report_security_check_mediafilterswf',
47 'report_security_check_openprofiles',
48 'report_security_check_google',
49 'report_security_check_passwordpolicy',
50 'report_security_check_emailchangeconfirmation',
51 'report_security_check_cookiesecure',
52 'report_security_check_configrw',
53 'report_security_check_riskxss',
54 'report_security_check_riskadmin',
55 'report_security_check_riskbackup',
56 'report_security_check_defaultuserrole',
57 'report_security_check_guestrole',
58 'report_security_check_frontpagerole',
59 'report_security_check_webcron',
64 function report_security_doc_link($issue, $name) {
65 global $CFG, $OUTPUT;
67 if (empty($CFG->docroot)) {
68 return $name;
71 return $OUTPUT->doc_link('report/security/'.$issue, $name);
74 ///=============================================
75 /// Issue checks
76 ///=============================================
79 /**
80 * Verifies unsupported noauth setting
81 * @param bool $detailed
82 * @return object result
84 function report_security_check_noauth($detailed=false) {
85 global $CFG;
87 $result = new stdClass();
88 $result->issue = 'report_security_check_noauth';
89 $result->name = get_string('check_noauth_name', 'report_security');
90 $result->info = null;
91 $result->details = null;
92 $result->status = null;
93 $result->link = null;
94 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=manageauths\">".get_string('authsettings', 'admin').'</a>';
96 if (is_enabled_auth('none')) {
97 $result->status = REPORT_SECURITY_CRITICAL;
98 $result->info = get_string('check_noauth_error', 'report_security');
99 } else {
100 $result->status = REPORT_SECURITY_OK;
101 $result->info = get_string('check_noauth_ok', 'report_security');
104 if ($detailed) {
105 $result->details = get_string('check_noauth_details', 'report_security');
108 return $result;
112 * Verifies if password policy set
113 * @param bool $detailed
114 * @return object result
116 function report_security_check_passwordpolicy($detailed=false) {
117 global $CFG;
119 $result = new stdClass();
120 $result->issue = 'report_security_check_passwordpolicy';
121 $result->name = get_string('check_passwordpolicy_name', 'report_security');
122 $result->info = null;
123 $result->details = null;
124 $result->status = null;
125 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>';
127 if (empty($CFG->passwordpolicy)) {
128 $result->status = REPORT_SECURITY_WARNING;
129 $result->info = get_string('check_passwordpolicy_error', 'report_security');
130 } else {
131 $result->status = REPORT_SECURITY_OK;
132 $result->info = get_string('check_passwordpolicy_ok', 'report_security');
135 if ($detailed) {
136 $result->details = get_string('check_passwordpolicy_details', 'report_security');
139 return $result;
143 * Verifies sloppy embedding - this should have been removed long ago!!
144 * @param bool $detailed
145 * @return object result
147 function report_security_check_embed($detailed=false) {
148 global $CFG;
150 $result = new stdClass();
151 $result->issue = 'report_security_check_embed';
152 $result->name = get_string('check_embed_name', 'report_security');
153 $result->info = null;
154 $result->details = null;
155 $result->status = null;
156 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>';
158 if (!empty($CFG->allowobjectembed)) {
159 $result->status = REPORT_SECURITY_CRITICAL;
160 $result->info = get_string('check_embed_error', 'report_security');
161 } else {
162 $result->status = REPORT_SECURITY_OK;
163 $result->info = get_string('check_embed_ok', 'report_security');
166 if ($detailed) {
167 $result->details = get_string('check_embed_details', 'report_security');
170 return $result;
174 * Verifies sloppy swf embedding - this should have been removed long ago!!
175 * @param bool $detailed
176 * @return object result
178 function report_security_check_mediafilterswf($detailed=false) {
179 global $CFG;
181 $result = new stdClass();
182 $result->issue = 'report_security_check_mediafilterswf';
183 $result->name = get_string('check_mediafilterswf_name', 'report_security');
184 $result->info = null;
185 $result->details = null;
186 $result->status = null;
187 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=managemediaplayers\">" .
188 get_string('managemediaplayers', 'media') . '</a>';
190 $activefilters = filter_get_globally_enabled();
192 $enabledmediaplayers = \core\plugininfo\media::get_enabled_plugins();
193 if (array_search('mediaplugin', $activefilters) !== false and array_key_exists('swf', $enabledmediaplayers)) {
194 $result->status = REPORT_SECURITY_CRITICAL;
195 $result->info = get_string('check_mediafilterswf_error', 'report_security');
196 } else {
197 $result->status = REPORT_SECURITY_OK;
198 $result->info = get_string('check_mediafilterswf_ok', 'report_security');
201 if ($detailed) {
202 $result->details = get_string('check_mediafilterswf_details', 'report_security');
205 return $result;
209 * Verifies fatal misconfiguration of dataroot
210 * @param bool $detailed
211 * @return object result
213 function report_security_check_unsecuredataroot($detailed=false) {
214 global $CFG;
216 $result = new stdClass();
217 $result->issue = 'report_security_check_unsecuredataroot';
218 $result->name = get_string('check_unsecuredataroot_name', 'report_security');
219 $result->info = null;
220 $result->details = null;
221 $result->status = null;
222 $result->link = null;
224 $insecuredataroot = is_dataroot_insecure(true);
226 if ($insecuredataroot == INSECURE_DATAROOT_WARNING) {
227 $result->status = REPORT_SECURITY_SERIOUS;
228 $result->info = get_string('check_unsecuredataroot_warning', 'report_security', $CFG->dataroot);
230 } else if ($insecuredataroot == INSECURE_DATAROOT_ERROR) {
231 $result->status = REPORT_SECURITY_CRITICAL;
232 $result->info = get_string('check_unsecuredataroot_error', 'report_security', $CFG->dataroot);
234 } else {
235 $result->status = REPORT_SECURITY_OK;
236 $result->info = get_string('check_unsecuredataroot_ok', 'report_security');
239 if ($detailed) {
240 $result->details = get_string('check_unsecuredataroot_details', 'report_security');
243 return $result;
247 * Verifies displaying of errors - problem for lib files and 3rd party code
248 * because we can not disable debugging in these scripts (they do not include config.php)
249 * @param bool $detailed
250 * @return object result
252 function report_security_check_displayerrors($detailed=false) {
253 $result = new stdClass();
254 $result->issue = 'report_security_check_displayerrors';
255 $result->name = get_string('check_displayerrors_name', 'report_security');
256 $result->info = null;
257 $result->details = null;
258 $result->status = null;
259 $result->link = null;
261 if (defined('WARN_DISPLAY_ERRORS_ENABLED')) {
262 $result->status = REPORT_SECURITY_WARNING;
263 $result->info = get_string('check_displayerrors_error', 'report_security');
264 } else {
265 $result->status = REPORT_SECURITY_OK;
266 $result->info = get_string('check_displayerrors_ok', 'report_security');
269 if ($detailed) {
270 $result->details = get_string('check_displayerrors_details', 'report_security');
273 return $result;
277 * Verifies open profiles - originally open by default, not anymore because spammer abused it a lot
278 * @param bool $detailed
279 * @return object result
281 function report_security_check_openprofiles($detailed=false) {
282 global $CFG;
284 $result = new stdClass();
285 $result->issue = 'report_security_check_openprofiles';
286 $result->name = get_string('check_openprofiles_name', 'report_security');
287 $result->info = null;
288 $result->details = null;
289 $result->status = null;
290 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>';
292 if (empty($CFG->forcelogin) and empty($CFG->forceloginforprofiles)) {
293 $result->status = REPORT_SECURITY_WARNING;
294 $result->info = get_string('check_openprofiles_error', 'report_security');
295 } else {
296 $result->status = REPORT_SECURITY_OK;
297 $result->info = get_string('check_openprofiles_ok', 'report_security');
300 if ($detailed) {
301 $result->details = get_string('check_openprofiles_details', 'report_security');
304 return $result;
308 * Verifies google access not combined with disabled guest access
309 * because attackers might gain guest access by modifying browser signature.
310 * @param bool $detailed
311 * @return object result
313 function report_security_check_google($detailed=false) {
314 global $CFG;
316 $result = new stdClass();
317 $result->issue = 'report_security_check_google';
318 $result->name = get_string('check_google_name', 'report_security');
319 $result->info = null;
320 $result->details = null;
321 $result->status = null;
322 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>';
324 if (empty($CFG->opentogoogle)) {
325 $result->status = REPORT_SECURITY_OK;
326 $result->info = get_string('check_google_ok', 'report_security');
327 } else if (!empty($CFG->guestloginbutton)) {
328 $result->status = REPORT_SECURITY_INFO;
329 $result->info = get_string('check_google_info', 'report_security');
330 } else {
331 $result->status = REPORT_SECURITY_SERIOUS;
332 $result->info = get_string('check_google_error', 'report_security');
335 if ($detailed) {
336 $result->details = get_string('check_google_details', 'report_security');
339 return $result;
343 * Verifies email confirmation - spammers were changing mails very often
344 * @param bool $detailed
345 * @return object result
347 function report_security_check_emailchangeconfirmation($detailed=false) {
348 global $CFG;
350 $result = new stdClass();
351 $result->issue = 'report_security_check_emailchangeconfirmation';
352 $result->name = get_string('check_emailchangeconfirmation_name', 'report_security');
353 $result->info = null;
354 $result->details = null;
355 $result->status = null;
356 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>';
358 if (empty($CFG->emailchangeconfirmation)) {
359 if (empty($CFG->allowemailaddresses)) {
360 $result->status = REPORT_SECURITY_WARNING;
361 $result->info = get_string('check_emailchangeconfirmation_error', 'report_security');
362 } else {
363 $result->status = REPORT_SECURITY_INFO;
364 $result->info = get_string('check_emailchangeconfirmation_info', 'report_security');
366 } else {
367 $result->status = REPORT_SECURITY_OK;
368 $result->info = get_string('check_emailchangeconfirmation_ok', 'report_security');
371 if ($detailed) {
372 $result->details = get_string('check_emailchangeconfirmation_details', 'report_security');
375 return $result;
379 * Verifies if https enabled only secure cookies allowed,
380 * this prevents redirections and sending of cookies to unsecure port.
381 * @param bool $detailed
382 * @return object result
384 function report_security_check_cookiesecure($detailed=false) {
385 global $CFG;
387 if (!is_https()) {
388 return null;
391 $result = new stdClass();
392 $result->issue = 'report_security_check_cookiesecure';
393 $result->name = get_string('check_cookiesecure_name', 'report_security');
394 $result->info = null;
395 $result->details = null;
396 $result->status = null;
397 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=httpsecurity\">".get_string('httpsecurity', 'admin').'</a>';
399 if (!is_moodle_cookie_secure()) {
400 $result->status = REPORT_SECURITY_SERIOUS;
401 $result->info = get_string('check_cookiesecure_error', 'report_security');
402 } else {
403 $result->status = REPORT_SECURITY_OK;
404 $result->info = get_string('check_cookiesecure_ok', 'report_security');
407 if ($detailed) {
408 $result->details = get_string('check_cookiesecure_details', 'report_security');
411 return $result;
415 * Verifies config.php is not writable anymore after installation,
416 * config files were changed on several outdated server.
417 * @param bool $detailed
418 * @return object result
420 function report_security_check_configrw($detailed=false) {
421 global $CFG;
423 $result = new stdClass();
424 $result->issue = 'report_security_check_configrw';
425 $result->name = get_string('check_configrw_name', 'report_security');
426 $result->info = null;
427 $result->details = null;
428 $result->status = null;
429 $result->link = null;
431 if (is_writable($CFG->dirroot.'/config.php')) {
432 $result->status = REPORT_SECURITY_WARNING;
433 $result->info = get_string('check_configrw_warning', 'report_security');
434 } else {
435 $result->status = REPORT_SECURITY_OK;
436 $result->info = get_string('check_configrw_ok', 'report_security');
439 if ($detailed) {
440 $result->details = get_string('check_configrw_details', 'report_security');
443 return $result;
448 * Lists all users with XSS risk, it would be great to combine this with risk trusts in user table,
449 * unfortunately nobody implemented user trust UI yet :-(
450 * @param bool $detailed
451 * @return object result
453 function report_security_check_riskxss($detailed=false) {
454 global $DB;
456 $result = new stdClass();
457 $result->issue = 'report_security_check_riskxss';
458 $result->name = get_string('check_riskxss_name', 'report_security');
459 $result->info = null;
460 $result->details = null;
461 $result->status = REPORT_SECURITY_WARNING;
462 $result->link = null;
464 $params = array('capallow'=>CAP_ALLOW);
466 $sqlfrom = "FROM (SELECT rcx.*
467 FROM {role_capabilities} rcx
468 JOIN {capabilities} cap ON (cap.name = rcx.capability AND ".$DB->sql_bitand('cap.riskbitmask', RISK_XSS)." <> 0)
469 WHERE rcx.permission = :capallow) rc,
470 {context} c,
471 {context} sc,
472 {role_assignments} ra,
473 {user} u
474 WHERE c.id = rc.contextid
475 AND (sc.path = c.path OR sc.path LIKE ".$DB->sql_concat('c.path', "'/%'")." OR c.path LIKE ".$DB->sql_concat('sc.path', "'/%'").")
476 AND u.id = ra.userid AND u.deleted = 0
477 AND ra.contextid = sc.id AND ra.roleid = rc.roleid";
479 $count = $DB->count_records_sql("SELECT COUNT(DISTINCT u.id) $sqlfrom", $params);
481 $result->info = get_string('check_riskxss_warning', 'report_security', $count);
483 if ($detailed) {
484 $userfields = user_picture::fields('u');
485 $users = $DB->get_records_sql("SELECT DISTINCT $userfields $sqlfrom", $params);
486 foreach ($users as $uid=>$user) {
487 $users[$uid] = fullname($user);
489 $users = implode(', ', $users);
490 $result->details = get_string('check_riskxss_details', 'report_security', $users);
493 return $result;
497 * Verifies sanity of default user role.
498 * @param bool $detailed
499 * @return object result
501 function report_security_check_defaultuserrole($detailed=false) {
502 global $DB, $CFG;
504 $result = new stdClass();
505 $result->issue = 'report_security_check_defaultuserrole';
506 $result->name = get_string('check_defaultuserrole_name', 'report_security');
507 $result->info = null;
508 $result->details = null;
509 $result->status = null;
510 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies\">".get_string('userpolicies', 'admin').'</a>';
512 if (!$default_role = $DB->get_record('role', array('id'=>$CFG->defaultuserroleid))) {
513 $result->status = REPORT_SECURITY_WARNING;
514 $result->info = get_string('check_defaultuserrole_notset', 'report_security');
515 $result->details = $result->info;
517 return $result;
520 // risky caps - usually very dangerous
521 $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$default_role->id);
522 $sql = "SELECT COUNT(DISTINCT rc.contextid)
523 FROM {role_capabilities} rc
524 JOIN {capabilities} cap ON cap.name = rc.capability
525 WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))." <> 0
526 AND rc.permission = :capallow
527 AND rc.roleid = :roleid";
529 $riskycount = $DB->count_records_sql($sql, $params);
531 // it may have either none or 'user' archetype - nothing else, or else it would break during upgrades badly
532 if ($default_role->archetype === '' or $default_role->archetype === 'user') {
533 $legacyok = true;
534 } else {
535 $legacyok = false;
538 if ($riskycount or !$legacyok) {
539 $result->status = REPORT_SECURITY_CRITICAL;
540 $result->info = get_string('check_defaultuserrole_error', 'report_security', role_get_name($default_role));
542 } else {
543 $result->status = REPORT_SECURITY_OK;
544 $result->info = get_string('check_defaultuserrole_ok', 'report_security');
547 if ($detailed) {
548 $result->details = get_string('check_defaultuserrole_details', 'report_security');
551 return $result;
555 * Verifies sanity of guest role
556 * @param bool $detailed
557 * @return object result
559 function report_security_check_guestrole($detailed=false) {
560 global $DB, $CFG;
562 $result = new stdClass();
563 $result->issue = 'report_security_check_guestrole';
564 $result->name = get_string('check_guestrole_name', 'report_security');
565 $result->info = null;
566 $result->details = null;
567 $result->status = null;
568 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies\">".get_string('userpolicies', 'admin').'</a>';
570 if (!$guest_role = $DB->get_record('role', array('id'=>$CFG->guestroleid))) {
571 $result->status = REPORT_SECURITY_WARNING;
572 $result->info = get_string('check_guestrole_notset', 'report_security');
573 $result->details = $result->info;
575 return $result;
578 // risky caps - usually very dangerous
579 $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$guest_role->id);
580 $sql = "SELECT COUNT(DISTINCT rc.contextid)
581 FROM {role_capabilities} rc
582 JOIN {capabilities} cap ON cap.name = rc.capability
583 WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))." <> 0
584 AND rc.permission = :capallow
585 AND rc.roleid = :roleid";
587 $riskycount = $DB->count_records_sql($sql, $params);
589 // it may have either no or 'guest' archetype - nothing else, or else it would break during upgrades badly
590 if ($guest_role->archetype === '' or $guest_role->archetype === 'guest') {
591 $legacyok = true;
592 } else {
593 $legacyok = false;
596 if ($riskycount or !$legacyok) {
597 $result->status = REPORT_SECURITY_CRITICAL;
598 $result->info = get_string('check_guestrole_error', 'report_security', format_string($guest_role->name));
600 } else {
601 $result->status = REPORT_SECURITY_OK;
602 $result->info = get_string('check_guestrole_ok', 'report_security');
605 if ($detailed) {
606 $result->details = get_string('check_guestrole_details', 'report_security');
609 return $result;
613 * Verifies sanity of frontpage role
614 * @param bool $detailed
615 * @return object result
617 function report_security_check_frontpagerole($detailed=false) {
618 global $DB, $CFG;
620 $result = new stdClass();
621 $result->issue = 'report_security_check_frontpagerole';
622 $result->name = get_string('check_frontpagerole_name', 'report_security');
623 $result->info = null;
624 $result->details = null;
625 $result->status = null;
626 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=frontpagesettings\">".get_string('frontpagesettings','admin').'</a>';
628 if (!$frontpage_role = $DB->get_record('role', array('id'=>$CFG->defaultfrontpageroleid))) {
629 $result->status = REPORT_SECURITY_INFO;
630 $result->info = get_string('check_frontpagerole_notset', 'report_security');
631 $result->details = get_string('check_frontpagerole_details', 'report_security');
633 return $result;
636 // risky caps - usually very dangerous
637 $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$frontpage_role->id);
638 $sql = "SELECT COUNT(DISTINCT rc.contextid)
639 FROM {role_capabilities} rc
640 JOIN {capabilities} cap ON cap.name = rc.capability
641 WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))." <> 0
642 AND rc.permission = :capallow
643 AND rc.roleid = :roleid";
645 $riskycount = $DB->count_records_sql($sql, $params);
647 // there is no legacy role type for frontpage yet - anyway we can not allow teachers or admins there!
648 if ($frontpage_role->archetype === 'teacher' or $frontpage_role->archetype === 'editingteacher'
649 or $frontpage_role->archetype === 'coursecreator' or $frontpage_role->archetype === 'manager') {
650 $legacyok = false;
651 } else {
652 $legacyok = true;
655 if ($riskycount or !$legacyok) {
656 $result->status = REPORT_SECURITY_CRITICAL;
657 $result->info = get_string('check_frontpagerole_error', 'report_security', format_string($frontpage_role->name));
659 } else {
660 $result->status = REPORT_SECURITY_OK;
661 $result->info = get_string('check_frontpagerole_ok', 'report_security');
664 if ($detailed) {
665 $result->details = get_string('check_frontpagerole_details', 'report_security');
668 return $result;
672 * Lists all admins.
673 * @param bool $detailed
674 * @return object result
676 function report_security_check_riskadmin($detailed=false) {
677 global $DB, $CFG;
679 $result = new stdClass();
680 $result->issue = 'report_security_check_riskadmin';
681 $result->name = get_string('check_riskadmin_name', 'report_security');
682 $result->info = null;
683 $result->details = null;
684 $result->status = null;
685 $result->link = null;
687 $userfields = user_picture::fields('u');
688 $sql = "SELECT $userfields
689 FROM {user} u
690 WHERE u.id IN ($CFG->siteadmins)";
692 $admins = $DB->get_records_sql($sql);
693 $admincount = count($admins);
695 if ($detailed) {
696 foreach ($admins as $uid=>$user) {
697 $url = "$CFG->wwwroot/user/view.php?id=$user->id";
698 $admins[$uid] = '<li><a href="'.$url.'">'.fullname($user).' ('.$user->email.')</a></li>';
700 $admins = '<ul>'.implode('', $admins).'</ul>';
703 $result->status = REPORT_SECURITY_OK;
704 $result->info = get_string('check_riskadmin_ok', 'report_security', $admincount);
706 if ($detailed) {
707 $result->details = get_string('check_riskadmin_detailsok', 'report_security', $admins);
710 return $result;
714 * Lists all roles that have the ability to backup user data, as well as users
715 * @param bool $detailed
716 * @return object result
718 function report_security_check_riskbackup($detailed=false) {
719 global $CFG, $DB;
721 $result = new stdClass();
722 $result->issue = 'report_security_check_riskbackup';
723 $result->name = get_string('check_riskbackup_name', 'report_security');
724 $result->info = null;
725 $result->details = null;
726 $result->status = null;
727 $result->link = null;
729 $syscontext = context_system::instance();
731 $params = array('capability'=>'moodle/backup:userinfo', 'permission'=>CAP_ALLOW, 'contextid'=>$syscontext->id);
732 $sql = "SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder, r.archetype
733 FROM {role} r
734 JOIN {role_capabilities} rc ON rc.roleid = r.id
735 WHERE rc.capability = :capability
736 AND rc.contextid = :contextid
737 AND rc.permission = :permission";
738 $systemroles = $DB->get_records_sql($sql, $params);
740 $params = array('capability'=>'moodle/backup:userinfo', 'permission'=>CAP_ALLOW, 'contextid'=>$syscontext->id);
741 $sql = "SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder, r.archetype, rc.contextid
742 FROM {role} r
743 JOIN {role_capabilities} rc ON rc.roleid = r.id
744 WHERE rc.capability = :capability
745 AND rc.contextid <> :contextid
746 AND rc.permission = :permission";
747 $overriddenroles = $DB->get_records_sql($sql, $params);
749 // list of users that are able to backup personal info
750 // note: "sc" is context where is role assigned,
751 // "c" is context where is role overridden or system context if in role definition
752 $params = array('capability'=>'moodle/backup:userinfo', 'permission'=>CAP_ALLOW, 'context1'=>CONTEXT_COURSE, 'context2'=>CONTEXT_COURSE);
754 $sqluserinfo = "
755 FROM (SELECT rcx.*
756 FROM {role_capabilities} rcx
757 WHERE rcx.permission = :permission AND rcx.capability = :capability) rc,
758 {context} c,
759 {context} sc,
760 {role_assignments} ra,
761 {user} u
762 WHERE c.id = rc.contextid
763 AND (sc.path = c.path OR sc.path LIKE ".$DB->sql_concat('c.path', "'/%'")." OR c.path LIKE ".$DB->sql_concat('sc.path', "'/%'").")
764 AND u.id = ra.userid AND u.deleted = 0
765 AND ra.contextid = sc.id AND ra.roleid = rc.roleid
766 AND sc.contextlevel <= :context1 AND c.contextlevel <= :context2";
768 $usercount = $DB->count_records_sql("SELECT COUNT('x') FROM (SELECT DISTINCT u.id $sqluserinfo) userinfo", $params);
769 $systemrolecount = empty($systemroles) ? 0 : count($systemroles);
770 $overriddenrolecount = empty($overriddenroles) ? 0 : count($overriddenroles);
772 if (max($usercount, $systemrolecount, $overriddenrolecount) > 0) {
773 $result->status = REPORT_SECURITY_WARNING;
774 } else {
775 $result->status = REPORT_SECURITY_OK;
778 $a = (object)array('rolecount'=>$systemrolecount,'overridecount'=>$overriddenrolecount,'usercount'=>$usercount);
779 $result->info = get_string('check_riskbackup_warning', 'report_security', $a);
781 if ($detailed) {
783 $result->details = ''; // Will be added to later
785 // Make a list of roles
786 if ($systemroles) {
787 $links = array();
788 foreach ($systemroles as $role) {
789 $role->name = role_get_name($role);
790 $role->url = "$CFG->wwwroot/$CFG->admin/roles/manage.php?action=edit&amp;roleid=$role->id";
791 $links[] = '<li>'.get_string('check_riskbackup_editrole', 'report_security', $role).'</li>';
793 $links = '<ul>'.implode($links).'</ul>';
794 $result->details .= get_string('check_riskbackup_details_systemroles', 'report_security', $links);
797 // Make a list of overrides to roles
798 $rolelinks2 = array();
799 if ($overriddenroles) {
800 $links = array();
801 foreach ($overriddenroles as $role) {
802 $role->name = $role->localname;
803 $context = context::instance_by_id($role->contextid);
804 $role->name = role_get_name($role, $context, ROLENAME_BOTH);
805 $role->contextname = $context->get_context_name();
806 $role->url = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$role->contextid&amp;roleid=$role->id";
807 $links[] = '<li>'.get_string('check_riskbackup_editoverride', 'report_security', $role).'</li>';
809 $links = '<ul>'.implode('', $links).'</ul>';
810 $result->details .= get_string('check_riskbackup_details_overriddenroles', 'report_security', $links);
813 // Get a list of affected users as well
814 $users = array();
816 list($sort, $sortparams) = users_order_by_sql('u');
817 $userfields = user_picture::fields('u');
818 $rs = $DB->get_recordset_sql("SELECT DISTINCT $userfields, ra.contextid, ra.roleid
819 $sqluserinfo ORDER BY $sort", array_merge($params, $sortparams));
821 foreach ($rs as $user) {
822 $context = context::instance_by_id($user->contextid);
823 $url = "$CFG->wwwroot/$CFG->admin/roles/assign.php?contextid=$user->contextid&amp;roleid=$user->roleid";
824 $a = (object)array('fullname'=>fullname($user), 'url'=>$url, 'email'=>$user->email,
825 'contextname'=>$context->get_context_name());
826 $users[] = '<li>'.get_string('check_riskbackup_unassign', 'report_security', $a).'</li>';
828 if (!empty($users)) {
829 $users = '<ul>'.implode('', $users).'</ul>';
830 $result->details .= get_string('check_riskbackup_details_users', 'report_security', $users);
834 return $result;
838 * Verifies the status of web cron
840 * @param bool $detailed
841 * @return object result
843 function report_security_check_webcron($detailed = false) {
844 global $CFG;
846 $croncli = $CFG->cronclionly;
847 $cronremotepassword = $CFG->cronremotepassword;
849 $result = new stdClass();
850 $result->issue = 'report_security_check_webcron';
851 $result->name = get_string('check_webcron_name', 'report_security');
852 $result->details = null;
853 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">"
854 .get_string('sitepolicies', 'admin').'</a>';
856 if (empty($croncli) && empty($cronremotepassword)) {
857 $result->status = REPORT_SECURITY_WARNING;
858 $result->info = get_string('check_webcron_warning', 'report_security');
859 } else {
860 $result->status = REPORT_SECURITY_OK;
861 $result->info = get_string('check_webcron_ok', 'report_security');
864 if ($detailed) {
865 $result->details = get_string('check_webcron_details', 'report_security');
868 return $result;