[ Index ]

PHP Cross Reference of moodle-2.8

title

Body

[close]

/report/security/ -> locallib.php (source)

   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&amp;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&amp;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&amp;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  }


Generated: Fri Nov 28 20:29:05 2014 Cross-referenced by PHPXref 0.7.1