Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]

   1  <?php
   2  /**
   3   * An XML-RPC server
   4   *
   5   * @author  Donal McMullan  donal@catalyst.net.nz
   6   * @version 0.0.1
   7   * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
   8   * @package mnet
   9   */
  10  
  11  // Make certain that config.php doesn't display any errors, and that it doesn't
  12  // override our do-not-display-errors setting:
  13  // disable moodle specific debug messages and any errors in output
  14  define('NO_DEBUG_DISPLAY', true);
  15  // cookies are not used, makes sure there is empty global $USER
  16  define('NO_MOODLE_COOKIES', true);
  17  
  18  define('MNET_SERVER', true);
  19  
  20  require(__DIR__.'/../../config.php');
  21  
  22  $mnet = get_mnet_environment();
  23  // Include MNET stuff:
  24  require_once $CFG->dirroot.'/mnet/lib.php';
  25  require_once $CFG->dirroot.'/mnet/remote_client.php';
  26  require_once $CFG->dirroot.'/mnet/xmlrpc/serverlib.php';
  27  
  28  
  29  if ($CFG->mnet_dispatcher_mode === 'off') {
  30      throw new \moodle_exception('mnetdisabled', 'mnet');
  31  }
  32  
  33  // Content type for output is not html:
  34  header('Content-type: text/xml; charset=utf-8');
  35  
  36  $rawpostdata = file_get_contents("php://input");
  37  mnet_debug("RAW POST DATA", 2);
  38  mnet_debug($rawpostdata, 2);
  39  
  40  if (!isset($_SERVER)) {
  41      exit(mnet_server_fault(712, get_string('phperror', 'mnet')));
  42  }
  43  
  44  
  45  // New global variable which ONLY gets set in this server page, so you know that
  46  // if you've been called by a remote Moodle, this should be set:
  47  $remoteclient = new mnet_remote_client();
  48  set_mnet_remote_client($remoteclient);
  49  
  50  try {
  51      $plaintextmessage = mnet_server_strip_encryption($rawpostdata);
  52      $xmlrpcrequest = mnet_server_strip_signature($plaintextmessage);
  53  } catch (Exception $e) {
  54      mnet_debug('encryption strip exception thrown: ' . $e->getMessage());
  55      exit(mnet_server_fault($e->getCode(), $e->getMessage(), $e->a));
  56  }
  57  
  58  mnet_debug('XMLRPC Payload', 2);
  59  mnet_debug($xmlrpcrequest, 2);
  60  
  61  if($remoteclient->pushkey == true) {
  62      // The peer used one of our older public keys, we will return a
  63      // signed/encrypted error message containing our new public key
  64      // Sign message with our old key, and encrypt to the peer's private key.
  65      mnet_debug('sending back new key');
  66      exit(mnet_server_fault_xml(7025, $mnet->public_key, $remoteclient->useprivatekey));
  67  }
  68  // Have a peek at what the request would be if we were to process it
  69  $encoder = new \PhpXmlRpc\Encoder();
  70  $orequest = $encoder->decodeXML($xmlrpcrequest); // First, to internal.
  71  $method = $orequest->method(); // We just need the method.
  72  mnet_debug("incoming mnet request $method");
  73  
  74  // One of three conditions need to be met before we continue processing this request:
  75  // 1. Request is properly encrypted and signed
  76  // 2. Request is for a keyswap (we don't mind enencrypted or unsigned requests for a public key)
  77  // 3. Request is properly signed and we're happy with it being unencrypted
  78  if ((($remoteclient->request_was_encrypted == true) && ($remoteclient->signatureok == true))
  79      || (($method == 'system.keyswap') || ($method == 'system/keyswap'))
  80      || (($remoteclient->signatureok == true) && ($remoteclient->plaintext_is_ok() == true))) {
  81      try {
  82          // main dispatch call.  will echo the response directly
  83          mnet_server_dispatch($xmlrpcrequest);
  84          mnet_debug('exiting cleanly');
  85          exit;
  86      } catch (Exception $e) {
  87          mnet_debug('dispatch exception thrown: ' . $e->getMessage());
  88          exit(mnet_server_fault($e->getCode(), $e->getMessage(), $e->a));
  89      }
  90  }
  91  // if we get to here, something is wrong
  92  // so detect a few common cases and send appropriate errors
  93  if (($remoteclient->request_was_encrypted == false) && ($remoteclient->plaintext_is_ok() == false)) {
  94      mnet_debug('non encrypted request');
  95      exit(mnet_server_fault(7021, get_string('forbidden-transport', 'mnet')));
  96  }
  97  
  98  if ($remoteclient->request_was_signed == false) {
  99      // Request was not signed
 100      mnet_debug('non signed request');
 101      exit(mnet_server_fault(711, get_string('verifysignature-error', 'mnet')));
 102  }
 103  
 104  if ($remoteclient->signatureok == false) {
 105      // We were unable to verify the signature
 106      mnet_debug('non verified signature');
 107      exit(mnet_server_fault(710, get_string('verifysignature-invalid', 'mnet')));
 108  }
 109  mnet_debug('unknown error');
 110  exit(mnet_server_fault(7000, get_string('unknownerror', 'mnet')));