[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
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. 13 // 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/>. 16 17 /** 18 * Lib functions 19 * 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 24 */ 25 26 defined('MOODLE_INTERNAL') || die; 27 28 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'); 34 35 function report_security_hide_timearning() { 36 global $PAGE; 37 $PAGE->requires->js_init_code("Y.one('#timewarning').addClass('timewarninghidden')"); 38 } 39 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 60 ); 61 } 62 63 function report_security_doc_link($issue, $name) { 64 global $CFG, $OUTPUT; 65 66 if (empty($CFG->docroot)) { 67 return $name; 68 } 69 70 return $OUTPUT->doc_link('report/security/'.$issue, $name); 71 } 72 73 ///============================================= 74 /// Issue checks 75 ///============================================= 76 77 78 /** 79 * Verifies unsupported noauth setting 80 * @param bool $detailed 81 * @return object result 82 */ 83 function report_security_check_noauth($detailed=false) { 84 global $CFG; 85 86 $result = new stdClass(); 87 $result->issue = 'report_security_check_noauth'; 88 $result->name = get_string('check_noauth_name', 'report_security'); 89 $result->info = null; 90 $result->details = null; 91 $result->status = null; 92 $result->link = null; 93 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=manageauths\">".get_string('authsettings', 'admin').'</a>'; 94 95 if (is_enabled_auth('none')) { 96 $result->status = REPORT_SECURITY_CRITICAL; 97 $result->info = get_string('check_noauth_error', 'report_security'); 98 } else { 99 $result->status = REPORT_SECURITY_OK; 100 $result->info = get_string('check_noauth_ok', 'report_security'); 101 } 102 103 if ($detailed) { 104 $result->details = get_string('check_noauth_details', 'report_security'); 105 } 106 107 return $result; 108 } 109 110 /** 111 * Verifies if password policy set 112 * @param bool $detailed 113 * @return object result 114 */ 115 function report_security_check_passwordpolicy($detailed=false) { 116 global $CFG; 117 118 $result = new stdClass(); 119 $result->issue = 'report_security_check_passwordpolicy'; 120 $result->name = get_string('check_passwordpolicy_name', 'report_security'); 121 $result->info = null; 122 $result->details = null; 123 $result->status = null; 124 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>'; 125 126 if (empty($CFG->passwordpolicy)) { 127 $result->status = REPORT_SECURITY_WARNING; 128 $result->info = get_string('check_passwordpolicy_error', 'report_security'); 129 } else { 130 $result->status = REPORT_SECURITY_OK; 131 $result->info = get_string('check_passwordpolicy_ok', 'report_security'); 132 } 133 134 if ($detailed) { 135 $result->details = get_string('check_passwordpolicy_details', 'report_security'); 136 } 137 138 return $result; 139 } 140 141 /** 142 * Verifies sloppy embedding - this should have been removed long ago!! 143 * @param bool $detailed 144 * @return object result 145 */ 146 function report_security_check_embed($detailed=false) { 147 global $CFG; 148 149 $result = new stdClass(); 150 $result->issue = 'report_security_check_embed'; 151 $result->name = get_string('check_embed_name', 'report_security'); 152 $result->info = null; 153 $result->details = null; 154 $result->status = null; 155 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>'; 156 157 if (!empty($CFG->allowobjectembed)) { 158 $result->status = REPORT_SECURITY_CRITICAL; 159 $result->info = get_string('check_embed_error', 'report_security'); 160 } else { 161 $result->status = REPORT_SECURITY_OK; 162 $result->info = get_string('check_embed_ok', 'report_security'); 163 } 164 165 if ($detailed) { 166 $result->details = get_string('check_embed_details', 'report_security'); 167 } 168 169 return $result; 170 } 171 172 /** 173 * Verifies sloppy swf embedding - this should have been removed long ago!! 174 * @param bool $detailed 175 * @return object result 176 */ 177 function report_security_check_mediafilterswf($detailed=false) { 178 global $CFG; 179 180 $result = new stdClass(); 181 $result->issue = 'report_security_check_mediafilterswf'; 182 $result->name = get_string('check_mediafilterswf_name', 'report_security'); 183 $result->info = null; 184 $result->details = null; 185 $result->status = null; 186 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=filtersettingfiltermediaplugin\">".get_string('filtersettings', 'admin').'</a>'; 187 188 $activefilters = filter_get_globally_enabled(); 189 190 if (array_search('mediaplugin', $activefilters) !== false and !empty($CFG->filter_mediaplugin_enable_swf)) { 191 $result->status = REPORT_SECURITY_CRITICAL; 192 $result->info = get_string('check_mediafilterswf_error', 'report_security'); 193 } else { 194 $result->status = REPORT_SECURITY_OK; 195 $result->info = get_string('check_mediafilterswf_ok', 'report_security'); 196 } 197 198 if ($detailed) { 199 $result->details = get_string('check_mediafilterswf_details', 'report_security'); 200 } 201 202 return $result; 203 } 204 205 /** 206 * Verifies fatal misconfiguration of dataroot 207 * @param bool $detailed 208 * @return object result 209 */ 210 function report_security_check_unsecuredataroot($detailed=false) { 211 global $CFG; 212 213 $result = new stdClass(); 214 $result->issue = 'report_security_check_unsecuredataroot'; 215 $result->name = get_string('check_unsecuredataroot_name', 'report_security'); 216 $result->info = null; 217 $result->details = null; 218 $result->status = null; 219 $result->link = null; 220 221 $insecuredataroot = is_dataroot_insecure(true); 222 223 if ($insecuredataroot == INSECURE_DATAROOT_WARNING) { 224 $result->status = REPORT_SECURITY_SERIOUS; 225 $result->info = get_string('check_unsecuredataroot_warning', 'report_security', $CFG->dataroot); 226 227 } else if ($insecuredataroot == INSECURE_DATAROOT_ERROR) { 228 $result->status = REPORT_SECURITY_CRITICAL; 229 $result->info = get_string('check_unsecuredataroot_error', 'report_security', $CFG->dataroot); 230 231 } else { 232 $result->status = REPORT_SECURITY_OK; 233 $result->info = get_string('check_unsecuredataroot_ok', 'report_security'); 234 } 235 236 if ($detailed) { 237 $result->details = get_string('check_unsecuredataroot_details', 'report_security'); 238 } 239 240 return $result; 241 } 242 243 /** 244 * Verifies displaying of errors - problem for lib files and 3rd party code 245 * because we can not disable debugging in these scripts (they do not include config.php) 246 * @param bool $detailed 247 * @return object result 248 */ 249 function report_security_check_displayerrors($detailed=false) { 250 $result = new stdClass(); 251 $result->issue = 'report_security_check_displayerrors'; 252 $result->name = get_string('check_displayerrors_name', 'report_security'); 253 $result->info = null; 254 $result->details = null; 255 $result->status = null; 256 $result->link = null; 257 258 if (defined('WARN_DISPLAY_ERRORS_ENABLED')) { 259 $result->status = REPORT_SECURITY_WARNING; 260 $result->info = get_string('check_displayerrors_error', 'report_security'); 261 } else { 262 $result->status = REPORT_SECURITY_OK; 263 $result->info = get_string('check_displayerrors_ok', 'report_security'); 264 } 265 266 if ($detailed) { 267 $result->details = get_string('check_displayerrors_details', 'report_security'); 268 } 269 270 return $result; 271 } 272 273 /** 274 * Verifies open profiles - originally open by default, not anymore because spammer abused it a lot 275 * @param bool $detailed 276 * @return object result 277 */ 278 function report_security_check_openprofiles($detailed=false) { 279 global $CFG; 280 281 $result = new stdClass(); 282 $result->issue = 'report_security_check_openprofiles'; 283 $result->name = get_string('check_openprofiles_name', 'report_security'); 284 $result->info = null; 285 $result->details = null; 286 $result->status = null; 287 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>'; 288 289 if (empty($CFG->forcelogin) and empty($CFG->forceloginforprofiles)) { 290 $result->status = REPORT_SECURITY_WARNING; 291 $result->info = get_string('check_openprofiles_error', 'report_security'); 292 } else { 293 $result->status = REPORT_SECURITY_OK; 294 $result->info = get_string('check_openprofiles_ok', 'report_security'); 295 } 296 297 if ($detailed) { 298 $result->details = get_string('check_openprofiles_details', 'report_security'); 299 } 300 301 return $result; 302 } 303 304 /** 305 * Verifies google access not combined with disabled guest access 306 * because attackers might gain guest access by modifying browser signature. 307 * @param bool $detailed 308 * @return object result 309 */ 310 function report_security_check_google($detailed=false) { 311 global $CFG; 312 313 $result = new stdClass(); 314 $result->issue = 'report_security_check_google'; 315 $result->name = get_string('check_google_name', 'report_security'); 316 $result->info = null; 317 $result->details = null; 318 $result->status = null; 319 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>'; 320 321 if (empty($CFG->opentogoogle)) { 322 $result->status = REPORT_SECURITY_OK; 323 $result->info = get_string('check_google_ok', 'report_security'); 324 } else if (!empty($CFG->guestloginbutton)) { 325 $result->status = REPORT_SECURITY_INFO; 326 $result->info = get_string('check_google_info', 'report_security'); 327 } else { 328 $result->status = REPORT_SECURITY_SERIOUS; 329 $result->info = get_string('check_google_error', 'report_security'); 330 } 331 332 if ($detailed) { 333 $result->details = get_string('check_google_details', 'report_security'); 334 } 335 336 return $result; 337 } 338 339 /** 340 * Verifies email confirmation - spammers were changing mails very often 341 * @param bool $detailed 342 * @return object result 343 */ 344 function report_security_check_emailchangeconfirmation($detailed=false) { 345 global $CFG; 346 347 $result = new stdClass(); 348 $result->issue = 'report_security_check_emailchangeconfirmation'; 349 $result->name = get_string('check_emailchangeconfirmation_name', 'report_security'); 350 $result->info = null; 351 $result->details = null; 352 $result->status = null; 353 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=sitepolicies\">".get_string('sitepolicies', 'admin').'</a>'; 354 355 if (empty($CFG->emailchangeconfirmation)) { 356 if (empty($CFG->allowemailaddresses)) { 357 $result->status = REPORT_SECURITY_WARNING; 358 $result->info = get_string('check_emailchangeconfirmation_error', 'report_security'); 359 } else { 360 $result->status = REPORT_SECURITY_INFO; 361 $result->info = get_string('check_emailchangeconfirmation_info', 'report_security'); 362 } 363 } else { 364 $result->status = REPORT_SECURITY_OK; 365 $result->info = get_string('check_emailchangeconfirmation_ok', 'report_security'); 366 } 367 368 if ($detailed) { 369 $result->details = get_string('check_emailchangeconfirmation_details', 'report_security'); 370 } 371 372 return $result; 373 } 374 375 /** 376 * Verifies if https enabled only secure cookies allowed, 377 * this prevents redirections and sending of cookies to unsecure port. 378 * @param bool $detailed 379 * @return object result 380 */ 381 function report_security_check_cookiesecure($detailed=false) { 382 global $CFG; 383 384 if (!is_https()) { 385 return null; 386 } 387 388 $result = new stdClass(); 389 $result->issue = 'report_security_check_cookiesecure'; 390 $result->name = get_string('check_cookiesecure_name', 'report_security'); 391 $result->info = null; 392 $result->details = null; 393 $result->status = null; 394 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=httpsecurity\">".get_string('httpsecurity', 'admin').'</a>'; 395 396 if (empty($CFG->cookiesecure)) { 397 $result->status = REPORT_SECURITY_SERIOUS; 398 $result->info = get_string('check_cookiesecure_error', 'report_security'); 399 } else { 400 $result->status = REPORT_SECURITY_OK; 401 $result->info = get_string('check_cookiesecure_ok', 'report_security'); 402 } 403 404 if ($detailed) { 405 $result->details = get_string('check_cookiesecure_details', 'report_security'); 406 } 407 408 return $result; 409 } 410 411 /** 412 * Verifies config.php is not writable anymore after installation, 413 * config files were changed on several outdated server. 414 * @param bool $detailed 415 * @return object result 416 */ 417 function report_security_check_configrw($detailed=false) { 418 global $CFG; 419 420 $result = new stdClass(); 421 $result->issue = 'report_security_check_configrw'; 422 $result->name = get_string('check_configrw_name', 'report_security'); 423 $result->info = null; 424 $result->details = null; 425 $result->status = null; 426 $result->link = null; 427 428 if (is_writable($CFG->dirroot.'/config.php')) { 429 $result->status = REPORT_SECURITY_WARNING; 430 $result->info = get_string('check_configrw_warning', 'report_security'); 431 } else { 432 $result->status = REPORT_SECURITY_OK; 433 $result->info = get_string('check_configrw_ok', 'report_security'); 434 } 435 436 if ($detailed) { 437 $result->details = get_string('check_configrw_details', 'report_security'); 438 } 439 440 return $result; 441 } 442 443 444 /** 445 * Lists all users with XSS risk, it would be great to combine this with risk trusts in user table, 446 * unfortunately nobody implemented user trust UI yet :-( 447 * @param bool $detailed 448 * @return object result 449 */ 450 function report_security_check_riskxss($detailed=false) { 451 global $DB; 452 453 $result = new stdClass(); 454 $result->issue = 'report_security_check_riskxss'; 455 $result->name = get_string('check_riskxss_name', 'report_security'); 456 $result->info = null; 457 $result->details = null; 458 $result->status = REPORT_SECURITY_WARNING; 459 $result->link = null; 460 461 $params = array('capallow'=>CAP_ALLOW); 462 463 $sqlfrom = "FROM (SELECT rcx.* 464 FROM {role_capabilities} rcx 465 JOIN {capabilities} cap ON (cap.name = rcx.capability AND ".$DB->sql_bitand('cap.riskbitmask', RISK_XSS)." <> 0) 466 WHERE rcx.permission = :capallow) rc, 467 {context} c, 468 {context} sc, 469 {role_assignments} ra, 470 {user} u 471 WHERE c.id = rc.contextid 472 AND (sc.path = c.path OR sc.path LIKE ".$DB->sql_concat('c.path', "'/%'")." OR c.path LIKE ".$DB->sql_concat('sc.path', "'/%'").") 473 AND u.id = ra.userid AND u.deleted = 0 474 AND ra.contextid = sc.id AND ra.roleid = rc.roleid"; 475 476 $count = $DB->count_records_sql("SELECT COUNT(DISTINCT u.id) $sqlfrom", $params); 477 478 $result->info = get_string('check_riskxss_warning', 'report_security', $count); 479 480 if ($detailed) { 481 $userfields = user_picture::fields('u'); 482 $users = $DB->get_records_sql("SELECT DISTINCT $userfields $sqlfrom", $params); 483 foreach ($users as $uid=>$user) { 484 $users[$uid] = fullname($user); 485 } 486 $users = implode(', ', $users); 487 $result->details = get_string('check_riskxss_details', 'report_security', $users); 488 } 489 490 return $result; 491 } 492 493 /** 494 * Verifies sanity of default user role. 495 * @param bool $detailed 496 * @return object result 497 */ 498 function report_security_check_defaultuserrole($detailed=false) { 499 global $DB, $CFG; 500 501 $result = new stdClass(); 502 $result->issue = 'report_security_check_defaultuserrole'; 503 $result->name = get_string('check_defaultuserrole_name', 'report_security'); 504 $result->info = null; 505 $result->details = null; 506 $result->status = null; 507 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies\">".get_string('userpolicies', 'admin').'</a>'; 508 509 if (!$default_role = $DB->get_record('role', array('id'=>$CFG->defaultuserroleid))) { 510 $result->status = REPORT_SECURITY_WARNING; 511 $result->info = get_string('check_defaultuserrole_notset', 'report_security'); 512 $result->details = $result->info; 513 514 return $result; 515 } 516 517 // risky caps - usually very dangerous 518 $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$default_role->id); 519 $sql = "SELECT COUNT(DISTINCT rc.contextid) 520 FROM {role_capabilities} rc 521 JOIN {capabilities} cap ON cap.name = rc.capability 522 WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))." <> 0 523 AND rc.permission = :capallow 524 AND rc.roleid = :roleid"; 525 526 $riskycount = $DB->count_records_sql($sql, $params); 527 528 // it may have either none or 'user' archetype - nothing else, or else it would break during upgrades badly 529 if ($default_role->archetype === '' or $default_role->archetype === 'user') { 530 $legacyok = true; 531 } else { 532 $legacyok = false; 533 } 534 535 if ($riskycount or !$legacyok) { 536 $result->status = REPORT_SECURITY_CRITICAL; 537 $result->info = get_string('check_defaultuserrole_error', 'report_security', role_get_name($default_role)); 538 539 } else { 540 $result->status = REPORT_SECURITY_OK; 541 $result->info = get_string('check_defaultuserrole_ok', 'report_security'); 542 } 543 544 if ($detailed) { 545 $result->details = get_string('check_defaultuserrole_details', 'report_security'); 546 } 547 548 return $result; 549 } 550 551 /** 552 * Verifies sanity of guest role 553 * @param bool $detailed 554 * @return object result 555 */ 556 function report_security_check_guestrole($detailed=false) { 557 global $DB, $CFG; 558 559 $result = new stdClass(); 560 $result->issue = 'report_security_check_guestrole'; 561 $result->name = get_string('check_guestrole_name', 'report_security'); 562 $result->info = null; 563 $result->details = null; 564 $result->status = null; 565 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=userpolicies\">".get_string('userpolicies', 'admin').'</a>'; 566 567 if (!$guest_role = $DB->get_record('role', array('id'=>$CFG->guestroleid))) { 568 $result->status = REPORT_SECURITY_WARNING; 569 $result->info = get_string('check_guestrole_notset', 'report_security'); 570 $result->details = $result->info; 571 572 return $result; 573 } 574 575 // risky caps - usually very dangerous 576 $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$guest_role->id); 577 $sql = "SELECT COUNT(DISTINCT rc.contextid) 578 FROM {role_capabilities} rc 579 JOIN {capabilities} cap ON cap.name = rc.capability 580 WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))." <> 0 581 AND rc.permission = :capallow 582 AND rc.roleid = :roleid"; 583 584 $riskycount = $DB->count_records_sql($sql, $params); 585 586 // it may have either no or 'guest' archetype - nothing else, or else it would break during upgrades badly 587 if ($guest_role->archetype === '' or $guest_role->archetype === 'guest') { 588 $legacyok = true; 589 } else { 590 $legacyok = false; 591 } 592 593 if ($riskycount or !$legacyok) { 594 $result->status = REPORT_SECURITY_CRITICAL; 595 $result->info = get_string('check_guestrole_error', 'report_security', format_string($guest_role->name)); 596 597 } else { 598 $result->status = REPORT_SECURITY_OK; 599 $result->info = get_string('check_guestrole_ok', 'report_security'); 600 } 601 602 if ($detailed) { 603 $result->details = get_string('check_guestrole_details', 'report_security'); 604 } 605 606 return $result; 607 } 608 609 /** 610 * Verifies sanity of frontpage role 611 * @param bool $detailed 612 * @return object result 613 */ 614 function report_security_check_frontpagerole($detailed=false) { 615 global $DB, $CFG; 616 617 $result = new stdClass(); 618 $result->issue = 'report_security_check_frontpagerole'; 619 $result->name = get_string('check_frontpagerole_name', 'report_security'); 620 $result->info = null; 621 $result->details = null; 622 $result->status = null; 623 $result->link = "<a href=\"$CFG->wwwroot/$CFG->admin/settings.php?section=frontpagesettings\">".get_string('frontpagesettings','admin').'</a>'; 624 625 if (!$frontpage_role = $DB->get_record('role', array('id'=>$CFG->defaultfrontpageroleid))) { 626 $result->status = REPORT_SECURITY_INFO; 627 $result->info = get_string('check_frontpagerole_notset', 'report_security'); 628 $result->details = get_string('check_frontpagerole_details', 'report_security'); 629 630 return $result; 631 } 632 633 // risky caps - usually very dangerous 634 $params = array('capallow'=>CAP_ALLOW, 'roleid'=>$frontpage_role->id); 635 $sql = "SELECT COUNT(DISTINCT rc.contextid) 636 FROM {role_capabilities} rc 637 JOIN {capabilities} cap ON cap.name = rc.capability 638 WHERE ".$DB->sql_bitand('cap.riskbitmask', (RISK_XSS | RISK_CONFIG | RISK_DATALOSS))." <> 0 639 AND rc.permission = :capallow 640 AND rc.roleid = :roleid"; 641 642 $riskycount = $DB->count_records_sql($sql, $params); 643 644 // there is no legacy role type for frontpage yet - anyway we can not allow teachers or admins there! 645 if ($frontpage_role->archetype === 'teacher' or $frontpage_role->archetype === 'editingteacher' 646 or $frontpage_role->archetype === 'coursecreator' or $frontpage_role->archetype === 'manager') { 647 $legacyok = false; 648 } else { 649 $legacyok = true; 650 } 651 652 if ($riskycount or !$legacyok) { 653 $result->status = REPORT_SECURITY_CRITICAL; 654 $result->info = get_string('check_frontpagerole_error', 'report_security', format_string($frontpage_role->name)); 655 656 } else { 657 $result->status = REPORT_SECURITY_OK; 658 $result->info = get_string('check_frontpagerole_ok', 'report_security'); 659 } 660 661 if ($detailed) { 662 $result->details = get_string('check_frontpagerole_details', 'report_security'); 663 } 664 665 return $result; 666 } 667 668 /** 669 * Lists all admins. 670 * @param bool $detailed 671 * @return object result 672 */ 673 function report_security_check_riskadmin($detailed=false) { 674 global $DB, $CFG; 675 676 $result = new stdClass(); 677 $result->issue = 'report_security_check_riskadmin'; 678 $result->name = get_string('check_riskadmin_name', 'report_security'); 679 $result->info = null; 680 $result->details = null; 681 $result->status = null; 682 $result->link = null; 683 684 $userfields = user_picture::fields('u'); 685 $sql = "SELECT $userfields 686 FROM {user} u 687 WHERE u.id IN ($CFG->siteadmins)"; 688 689 $admins = $DB->get_records_sql($sql); 690 $admincount = count($admins); 691 692 if ($detailed) { 693 foreach ($admins as $uid=>$user) { 694 $url = "$CFG->wwwroot/user/view.php?id=$user->id"; 695 $admins[$uid] = '<li><a href="'.$url.'">'.fullname($user).' ('.$user->email.')</a></li>'; 696 } 697 $admins = '<ul>'.implode('', $admins).'</ul>'; 698 } 699 700 $result->status = REPORT_SECURITY_OK; 701 $result->info = get_string('check_riskadmin_ok', 'report_security', $admincount); 702 703 if ($detailed) { 704 $result->details = get_string('check_riskadmin_detailsok', 'report_security', $admins); 705 } 706 707 return $result; 708 } 709 710 /** 711 * Lists all roles that have the ability to backup user data, as well as users 712 * @param bool $detailed 713 * @return object result 714 */ 715 function report_security_check_riskbackup($detailed=false) { 716 global $CFG, $DB; 717 718 $result = new stdClass(); 719 $result->issue = 'report_security_check_riskbackup'; 720 $result->name = get_string('check_riskbackup_name', 'report_security'); 721 $result->info = null; 722 $result->details = null; 723 $result->status = null; 724 $result->link = null; 725 726 $syscontext = context_system::instance(); 727 728 $params = array('capability'=>'moodle/backup:userinfo', 'permission'=>CAP_ALLOW, 'contextid'=>$syscontext->id); 729 $sql = "SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder, r.archetype 730 FROM {role} r 731 JOIN {role_capabilities} rc ON rc.roleid = r.id 732 WHERE rc.capability = :capability 733 AND rc.contextid = :contextid 734 AND rc.permission = :permission"; 735 $systemroles = $DB->get_records_sql($sql, $params); 736 737 $params = array('capability'=>'moodle/backup:userinfo', 'permission'=>CAP_ALLOW, 'contextid'=>$syscontext->id); 738 $sql = "SELECT DISTINCT r.id, r.name, r.shortname, r.sortorder, r.archetype, rc.contextid 739 FROM {role} r 740 JOIN {role_capabilities} rc ON rc.roleid = r.id 741 WHERE rc.capability = :capability 742 AND rc.contextid <> :contextid 743 AND rc.permission = :permission"; 744 $overriddenroles = $DB->get_records_sql($sql, $params); 745 746 // list of users that are able to backup personal info 747 // note: "sc" is context where is role assigned, 748 // "c" is context where is role overridden or system context if in role definition 749 $params = array('capability'=>'moodle/backup:userinfo', 'permission'=>CAP_ALLOW, 'context1'=>CONTEXT_COURSE, 'context2'=>CONTEXT_COURSE); 750 751 $sqluserinfo = " 752 FROM (SELECT rcx.* 753 FROM {role_capabilities} rcx 754 WHERE rcx.permission = :permission AND rcx.capability = :capability) rc, 755 {context} c, 756 {context} sc, 757 {role_assignments} ra, 758 {user} u 759 WHERE c.id = rc.contextid 760 AND (sc.path = c.path OR sc.path LIKE ".$DB->sql_concat('c.path', "'/%'")." OR c.path LIKE ".$DB->sql_concat('sc.path', "'/%'").") 761 AND u.id = ra.userid AND u.deleted = 0 762 AND ra.contextid = sc.id AND ra.roleid = rc.roleid 763 AND sc.contextlevel <= :context1 AND c.contextlevel <= :context2"; 764 765 $usercount = $DB->count_records_sql("SELECT COUNT('x') FROM (SELECT DISTINCT u.id $sqluserinfo) userinfo", $params); 766 $systemrolecount = empty($systemroles) ? 0 : count($systemroles); 767 $overriddenrolecount = empty($overriddenroles) ? 0 : count($overriddenroles); 768 769 if (max($usercount, $systemrolecount, $overriddenrolecount) > 0) { 770 $result->status = REPORT_SECURITY_WARNING; 771 } else { 772 $result->status = REPORT_SECURITY_OK; 773 } 774 775 $a = (object)array('rolecount'=>$systemrolecount,'overridecount'=>$overriddenrolecount,'usercount'=>$usercount); 776 $result->info = get_string('check_riskbackup_warning', 'report_security', $a); 777 778 if ($detailed) { 779 780 $result->details = ''; // Will be added to later 781 782 // Make a list of roles 783 if ($systemroles) { 784 $links = array(); 785 foreach ($systemroles as $role) { 786 $role->name = role_get_name($role); 787 $role->url = "$CFG->wwwroot/$CFG->admin/roles/manage.php?action=edit&roleid=$role->id"; 788 $links[] = '<li>'.get_string('check_riskbackup_editrole', 'report_security', $role).'</li>'; 789 } 790 $links = '<ul>'.implode($links).'</ul>'; 791 $result->details .= get_string('check_riskbackup_details_systemroles', 'report_security', $links); 792 } 793 794 // Make a list of overrides to roles 795 $rolelinks2 = array(); 796 if ($overriddenroles) { 797 $links = array(); 798 foreach ($overriddenroles as $role) { 799 $role->name = $role->localname; 800 $context = context::instance_by_id($role->contextid); 801 $role->name = role_get_name($role, $context, ROLENAME_BOTH); 802 $role->contextname = $context->get_context_name(); 803 $role->url = "$CFG->wwwroot/$CFG->admin/roles/override.php?contextid=$role->contextid&roleid=$role->id"; 804 $links[] = '<li>'.get_string('check_riskbackup_editoverride', 'report_security', $role).'</li>'; 805 } 806 $links = '<ul>'.implode('', $links).'</ul>'; 807 $result->details .= get_string('check_riskbackup_details_overriddenroles', 'report_security', $links); 808 } 809 810 // Get a list of affected users as well 811 $users = array(); 812 813 list($sort, $sortparams) = users_order_by_sql('u'); 814 $userfields = user_picture::fields('u'); 815 $rs = $DB->get_recordset_sql("SELECT DISTINCT $userfields, ra.contextid, ra.roleid 816 $sqluserinfo ORDER BY $sort", array_merge($params, $sortparams)); 817 818 foreach ($rs as $user) { 819 $context = context::instance_by_id($user->contextid); 820 $url = "$CFG->wwwroot/$CFG->admin/roles/assign.php?contextid=$user->contextid&roleid=$user->roleid"; 821 $a = (object)array('fullname'=>fullname($user), 'url'=>$url, 'email'=>$user->email, 822 'contextname'=>$context->get_context_name()); 823 $users[] = '<li>'.get_string('check_riskbackup_unassign', 'report_security', $a).'</li>'; 824 } 825 if (!empty($users)) { 826 $users = '<ul>'.implode('', $users).'</ul>'; 827 $result->details .= get_string('check_riskbackup_details_users', 'report_security', $users); 828 } 829 } 830 831 return $result; 832 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |