diff --git a/admin/mnet/testclient.php b/admin/mnet/testclient.php
new file mode 100644
index 00000000000..1394c6322fa
--- /dev/null
+++ b/admin/mnet/testclient.php
@@ -0,0 +1,195 @@
+dirroot.'/mnet/xmlrpc/client.php';
+require_once($CFG->libdir.'/adminlib.php');
+include_once($CFG->dirroot.'/mnet/lib.php');
+
+if ($CFG->mnet_dispatcher_mode === 'off') {
+ print_error('mnetdisabled', 'mnet');
+}
+
+require_login();
+admin_externalpage_setup('mnettestclient');
+
+$context = get_context_instance(CONTEXT_SYSTEM);
+require_capability('moodle/site:config', $context);
+
+error_reporting(E_ALL);
+
+admin_externalpage_print_header();
+if (!extension_loaded('openssl')) {
+ print_error('requiresopenssl', 'mnet', '', NULL, true);
+}
+
+// optional drilling down parameters
+$hostid = optional_param('hostid', 0, PARAM_INT);
+$servicename = optional_param('servicename', '', PARAM_SAFEDIR);
+$methodid = optional_param('method', 0, PARAM_INT);
+
+$hosts = $DB->get_records('mnet_host');
+$moodleapplicationid = $DB->get_field('mnet_application', 'id', array('name' => 'moodle'));
+
+$url = new moodle_url('/admin/mnet/testclient.php');
+$PAGE->set_url($url);
+
+echo $OUTPUT->heading(get_string('hostlist', 'mnet'));
+foreach ($hosts as $id => $host) {
+ if (empty($host->wwwroot) || $host->wwwroot == $CFG->wwwroot) {
+ continue;
+ }
+ $newurl = new moodle_url($url, array('hostid' => $host->id));
+ echo '
' . $OUTPUT->link($newurl, $host->wwwroot) . '
';
+}
+
+if (!empty($hostid) && array_key_exists($hostid, $hosts)) {
+ $host = $hosts[$hostid];
+ if ($host->applicationid != $moodleapplicationid) {
+ echo $OUTPUT->notification(get_string('notmoodleapplication', 'mnet'));
+ }
+ $mnet_peer = new mnet_peer();
+ $mnet_peer->set_wwwroot($host->wwwroot);
+
+ $mnet_request = new mnet_xmlrpc_client();
+
+ $mnet_request->set_method('system/listServices');
+ $mnet_request->send($mnet_peer);
+ $services = $mnet_request->response;
+ $yesno = array('No', 'Yes');
+ $servicenames = array();
+
+ echo $OUTPUT->heading(get_string('servicesavailableonhost', 'mnet', $host->wwwroot));
+
+ $table = new html_table();
+ $table->head = array(
+ get_string('serviceid', 'mnet'),
+ get_string('service', 'mnet'),
+ get_string('version', 'mnet'),
+ get_string('theypublish', 'mnet'),
+ get_string('theysubscribe', 'mnet'),
+ get_string('options', 'mnet'),
+ );
+ $table->data = array();
+ $sql = 'SELECT s.name, min(r.plugintype) AS plugintype, min(r.pluginname) AS pluginname
+ FROM {mnet_service} s
+ JOIN {mnet_service2rpc} s2r ON s2r.serviceid = s.id
+ JOIN {mnet_rpc} r ON r.id = s2r.rpcid
+ GROUP BY s.name';
+
+ $yesno = array(get_string('no'), get_string('yes'));
+
+ $serviceinfo = $DB->get_records_sql($sql);
+ foreach ($services as $id => $servicedata) {
+ if (array_key_exists($servicedata['name'], $serviceinfo)) {
+ $service = $serviceinfo[$servicedata['name']];
+ $servicedata['humanname'] = get_string($servicedata['name'].'_name', $service->plugintype . '_' . $service->pluginname);
+ } else {
+ $servicedata['humanname'] = get_string('unknown', 'mnet');
+ }
+ $newurl = new moodle_url($url, array('hostid' => $host->id, 'servicename' => $servicedata['name']));
+ $table->data[] = array(
+ $servicedata['name'],
+ $servicedata['humanname'],
+ $servicedata['apiversion'],
+ $yesno[$servicedata['publish']],
+ $yesno[$servicedata['subscribe']],
+ $OUTPUT->link($newurl, get_string('listservices', 'mnet'))
+ );
+
+ }
+ echo $OUTPUT->table($table);
+
+
+ $mnet_request->set_method('system/listMethods');
+ if (isset($servicename) && array_key_exists($servicename, $serviceinfo)) {
+ echo $OUTPUT->heading(get_string('methodsavailableonhostinservice', 'mnet', array('host' => $host->wwwroot, 'service' => $servicename)));
+ $service = $serviceinfo[$servicename];
+ $mnet_request->add_param($servicename, 'string');
+ } else {
+ echo $OUTPUT->heading(get_string('methodsavailableonhost', 'mnet', $host->wwwroot));
+ }
+
+ $mnet_request->send($mnet_peer);
+ $methods = $mnet_request->response;
+
+
+ $table = new html_table();
+ $table->head = array(
+ get_string('method', 'mnet'),
+ get_string('options', 'mnet'),
+ );
+ $table->data = array();
+
+ foreach ($methods as $id => $method) {
+ $params = array('hostid' => $host->id, 'method' => $id);
+ if (isset($servicename)) {
+ $params['servicename'] = $servicename;
+ }
+ $newurl = new moodle_url($url, $params);
+ $table->data[] = array(
+ $method,
+ $OUTPUT->link($newurl, get_string('inspect', 'mnet'))
+ );
+ }
+ echo $OUTPUT->table($table);
+
+ if (isset($methodid) && array_key_exists($methodid, $methods)) {
+ $method = $methods[$methodid];
+
+ $mnet_request = new mnet_xmlrpc_client();
+ $mnet_request->set_method('system/methodSignature');
+ $mnet_request->add_param($method, 'string');
+ $mnet_request->send($mnet_peer);
+ $signature = $mnet_request->response;
+
+ echo $OUTPUT->heading(get_string('methodsignature', 'mnet', $method));
+
+ $table = new html_table();
+ $table->head = array(
+ get_string('position', 'mnet'),
+ get_string('name', 'mnet'),
+ get_string('type', 'mnet'),
+ get_string('description', 'mnet'),
+ );
+ $table->data = array();
+
+ $params = $signature['parameters'];
+ foreach ($params as $pos => $details) {
+ $table->data[] = array(
+ $pos,
+ $details['name'],
+ $details['type'],
+ $details['description'],
+ );
+ }
+ $table->data[] = array(
+ get_string('returnvalue', 'mnet'),
+ '',
+ $signature['return']['type'],
+ $signature['return']['description']
+ );
+
+ echo $OUTPUT->table($table);
+
+ $mnet_request->set_method('system/methodHelp');
+ $mnet_request->add_param($method, 'string');
+ $mnet_request->send($mnet_peer);
+ $help = $mnet_request->response;
+
+ echo $OUTPUT->heading(get_string('methodhelp', 'mnet', $method));
+ echo(str_replace('\n', '
',$help));
+ }
+}
+
+echo $OUTPUT->footer();
+?>
diff --git a/auth/mnet/db/mnet.php b/auth/mnet/db/mnet.php
new file mode 100644
index 00000000000..6a64312cbcd
--- /dev/null
+++ b/auth/mnet/db/mnet.php
@@ -0,0 +1,52 @@
+.
+
+
+/**
+ * This file contains the mnet services for the mnet authentication plugin
+ *
+ * @since 2.0
+ * @package moodlecore
+ * @subpackage auth
+ * @copyright 2010 Penny Leach
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$publishes = array(
+ 'sso_idp' => array(
+ 'apiversion' => 1,
+ 'classname' => 'auth_plugin_mnet',
+ 'filename' => 'auth.php',
+ 'methods' => array(
+ 'user_authorise',
+ 'keepalive_server',
+ 'kill_children',
+ 'refresh_log',
+ 'fetch_user_image',
+ 'fetch_theme_info',
+ 'update_enrolments',
+ ),
+ ),
+ 'sso_sp' => array(
+ 'apiversion' => 1,
+ 'classname' => 'auth_plugin_mnet',
+ 'filename' => 'auth.php',
+ 'methods' => array(
+ 'keepalive_client',
+ 'kill_child'
+ )
+ )
+);
diff --git a/enrol/mnet/db/mnet.php b/enrol/mnet/db/mnet.php
new file mode 100644
index 00000000000..7edace29b1f
--- /dev/null
+++ b/enrol/mnet/db/mnet.php
@@ -0,0 +1,41 @@
+.
+
+
+/**
+ * This file contains the mnet services for the mnet enrolment plugin
+ *
+ * @since 2.0
+ * @package moodlecore
+ * @subpackage enrolment
+ * @copyright 2010 Penny Leach
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$publishes = array(
+ 'mnet_enrol' => array(
+ 'apiversion' => 1,
+ 'classname' => 'enrolment_plugin_mnet',
+ 'filename' => 'enrol.php',
+ 'methods' => array(
+ 'available_courses',
+ 'user_enrolments',
+ 'enrol_user',
+ 'unenrol_user',
+ 'course_enrolments'
+ ),
+ ),
+);
diff --git a/enrol/mnet/version.php b/enrol/mnet/version.php
new file mode 100644
index 00000000000..73d25f9b7a6
--- /dev/null
+++ b/enrol/mnet/version.php
@@ -0,0 +1,3 @@
+version = 2010012600;
diff --git a/mnet/rpclib.php b/mnet/rpclib.php
deleted file mode 100644
index b56a3a4de7b..00000000000
--- a/mnet/rpclib.php
+++ /dev/null
@@ -1,78 +0,0 @@
-first = 'last';
- $this->last = 'first';
- }
-
- function augment_first($newval) {
- $this->first = $this->first.$newval;
- return $this->first;
- }
-
- function augment_first_RPC_OK() {
- return true;
- }
-
- function mnet_concatenate_strings_RPC_OK() {
- return true;
- }
- function mnet_concatenate_strings($string1='', $string2='', $string3='') {
- return $string1.$string2.$string3;
- }
-}
diff --git a/mnet/testclient.php b/mnet/testclient.php
deleted file mode 100644
index 6b8bbf938bb..00000000000
--- a/mnet/testclient.php
+++ /dev/null
@@ -1,144 +0,0 @@
-dirroot.'/mnet/xmlrpc/client.php';
-
-if ($CFG->mnet_dispatcher_mode === 'off') {
- print_error('mnetdisabled', 'mnet');
-}
-
-// Site admins only, thanks.
-require_login();
-$context = get_context_instance(CONTEXT_SYSTEM);
-require_capability('moodle/site:config', $context);
-
-error_reporting(E_ALL);
-
-// Some HTML sugar
-echo '';
-?>
-
-
-Moodle MNET Test Client
-Hosts
-get_records('mnet_host');
-
-foreach ($hosts as $id => $host) {
- // Skip the 'all hosts' option
- if(empty($host->wwwroot)) continue;
- // Skip localhost
- if($host->wwwroot == $CFG->wwwroot) continue;
- // Skip non-moodle non-mahara hosts
- if($host->applicationid != 1 && $host->applicationid != 2) continue; //TODO: get rid of magic numbers.
- echo ''.$host->wwwroot."
\n";
-}
-
-if (!empty($_GET['hostid']) && array_key_exists($_GET['hostid'], $hosts)) {
- $host = $hosts[$_GET['hostid']];
- $mnet_peer = new mnet_peer();
- $mnet_peer->set_wwwroot($host->wwwroot);
-
- $mnet_request = new mnet_xmlrpc_client();
-
- // Tell it the path to the method that we want to execute
- $mnet_request->set_method('system/listServices');
- $mnet_request->send($mnet_peer);
- $services = $mnet_request->response;
- $yesno = array('No', 'Yes');
- $servicenames = array();
-
- echo '
Services available on host: '.$host->wwwroot .'
Service ID | Service | Version | They Publish | They Subscribe | |
';
- foreach ($services as $id => $service) {
- $sql = 'select c.id, c.parent_type, c.parent from {mnet_service2rpc} a, {mnet_service} b, {mnet_rpc} c where a.serviceid = b.id and b.name=? and c.id = a.rpcid ';
-
- echo '
- '.$service['name'].' | ';
- if ($detail = $DB->get_record_sql($sql, array($service['name']))) {
- $service['humanname'] = get_string($service['name'].'_name', $detail->parent_type.'_'.$detail->parent);
- echo ''.$service['humanname'].' | ';
- } else {
- $service['humanname'] = $service['name'];
- echo ' unknown | ';
- }
- echo '
- '.$service['apiversion'].' |
- '.$yesno[$service['publish']].' |
- '.$yesno[$service['subscribe']].' |
- List methods |
-
'."\n";
- $servicenames[$service['name']] = $service;
- }
- echo '
';
-
-
-
- if (isset($_GET['service']) && array_key_exists($_GET['service'], $servicenames)) {
- $service = $servicenames[$_GET['service']];
- // Tell it the path to the method that we want to execute
- $mnet_request->set_method('system/listMethods');
- $mnet_request->add_param($service['name'], 'string');
- $mnet_request->send($mnet_peer);
- $methods = $mnet_request->response;
-
- echo '
Methods in the '.$service['humanname'] .' service
Method | Options | ';
- foreach ($methods as $id => $method) {
- echo ''.$method.' | Inspect |
'."\n";
- }
- echo '
';
- } else {
- // Tell it the path to the method that we want to execute
- $mnet_request->set_method('system/listMethods');
- $mnet_request->send($mnet_peer);
- $methods = $mnet_request->response;
-
- echo '
Methods '.$host->wwwroot .'
Method | Options | ';
- foreach ($methods as $id => $method) {
- echo ''.$method.' | Inspect |
'."\n";
- }
- echo '
';
- }
-
- if (isset($_GET['method']) && array_key_exists($_GET['method'], $methods)) {
- $method = $methods[$_GET['method']];
-
- $mnet_request = new mnet_xmlrpc_client();
-
- // Tell it the path to the method that we want to execute
- $mnet_request->set_method('system/methodSignature');
- $mnet_request->add_param($method, 'string');
- $mnet_request->send($mnet_peer);
- $signature = $mnet_request->response;
- echo '
Method signature for '.$method.':
Position | Type | Description | ';
- $params = array_pop($signature);
- foreach ($params as $pos => $details) {
- echo ''.$pos.' | '.$details['type'].' | '.$details['description'].' |
';
- }
- echo '
';
-
- // Tell it the path to the method that we want to execute
- $mnet_request->set_method('system/methodHelp');
- $mnet_request->add_param($method, 'string');
- $mnet_request->send($mnet_peer);
- $help = $mnet_request->response;
- echo '
Help details from docblock for '.$method.':
';
- echo(str_replace('\n', '
',$help));
- echo '';
- }
-}
-
-
-?>
-
-
diff --git a/mnet/xmlrpc/serverlib.php b/mnet/xmlrpc/serverlib.php
new file mode 100644
index 00000000000..be0cef5194e
--- /dev/null
+++ b/mnet/xmlrpc/serverlib.php
@@ -0,0 +1,676 @@
+parse($HTTP_RAW_POST_DATA);
+
+ if (!$crypt_parser->payload_encrypted) {
+ return $HTTP_RAW_POST_DATA;
+ }
+
+ // Make sure we know who we're talking to
+ $host_record_exists = $MNET_REMOTE_CLIENT->set_wwwroot($crypt_parser->remote_wwwroot);
+
+ if (false == $host_record_exists) {
+ throw new mnet_server_exception(7020, 'wrong-wwwroot', $crypt_parser->remote_wwwroot);
+ }
+
+ // This key is symmetric, and is itself encrypted. Can be decrypted using our private key
+ $key = array_pop($crypt_parser->cipher);
+ // This data is symmetrically encrypted, can be decrypted using the above key
+ $data = array_pop($crypt_parser->cipher);
+
+ $crypt_parser->free_resource();
+ $payload = ''; // Initialize payload var
+
+ // &$payload
+ $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $MNET->get_private_key());
+ if ($isOpen) {
+ $MNET_REMOTE_CLIENT->was_encrypted();
+ return $payload;
+ }
+
+ // Decryption failed... let's try our archived keys
+ $openssl_history = get_config('mnet', 'openssl_history');
+ if(empty($openssl_history)) {
+ $openssl_history = array();
+ set_config('openssl_history', serialize($openssl_history), 'mnet');
+ } else {
+ $openssl_history = unserialize($openssl_history);
+ }
+ foreach($openssl_history as $keyset) {
+ $keyresource = openssl_pkey_get_private($keyset['keypair_PEM']);
+ $isOpen = openssl_open(base64_decode($data), $payload, base64_decode($key), $keyresource);
+ if ($isOpen) {
+ // It's an older code, sir, but it checks out
+
+ $MNET_REMOTE_CLIENT->was_encrypted();
+ $MNET_REMOTE_CLIENT->encrypted_to($keyresource);
+ $MNET_REMOTE_CLIENT->set_pushkey();
+ return $payload;
+ }
+ }
+
+ //If after all that we still couldn't decrypt the message, error out.
+ throw new mnet_server_exception(7023, 'encryption-invalid');
+}
+
+/* Strip signature envelope (if present), try to verify any signature using our record of remote peer's public key.
+ *
+ * @param string $plaintextmessage XML envelope containing XMLRPC request and signature
+ *
+ * @return string XMLRPC request
+ */
+function mnet_server_strip_signature($plaintextmessage) {
+ global $MNET, $MNET_REMOTE_CLIENT;
+ $sig_parser = new mnet_encxml_parser();
+ $sig_parser->parse($plaintextmessage);
+
+ if ($sig_parser->signature == '') {
+ return $plaintextmessage;
+ }
+
+ // Record that the request was signed in some way
+ $MNET_REMOTE_CLIENT->was_signed();
+
+ // Load any information we have about this mnet peer
+ $MNET_REMOTE_CLIENT->set_wwwroot($sig_parser->remote_wwwroot);
+
+ $payload = base64_decode($sig_parser->data_object);
+ $signature = base64_decode($sig_parser->signature);
+ $certificate = $MNET_REMOTE_CLIENT->public_key;
+
+ // If we don't have any certificate for the host, don't try to check the signature
+ // Just return the parsed request
+ if ($certificate == false) {
+ return $payload;
+ }
+
+ // Does the signature match the data and the public cert?
+ $signature_verified = openssl_verify($payload, $signature, $certificate);
+ if ($signature_verified == 0) {
+ // $signature was not generated for $payload using $certificate
+ // Get the key the remote peer is currently publishing:
+ $currkey = mnet_get_public_key($MNET_REMOTE_CLIENT->wwwroot, $MNET_REMOTE_CLIENT->application);
+ // If the key the remote peer is currently publishing is different to $certificate
+ if($currkey != $certificate) {
+ // Try and get the server's new key through trusted means
+ $MNET_REMOTE_CLIENT->refresh_key();
+ // If we did manage to re-key, try to verify the signature again using the new public key.
+ $certificate = $MNET_REMOTE_CLIENT->public_key;
+ $signature_verified = openssl_verify($payload, $signature, $certificate);
+ }
+ }
+
+ if ($signature_verified == 1) {
+ $MNET_REMOTE_CLIENT->signature_verified();
+ $MNET_REMOTE_CLIENT->touch();
+ }
+
+ $sig_parser->free_resource();
+
+ return $payload;
+}
+
+/**
+ * Return the proper XML-RPC content to report an error in the local language.
+ *
+ * @param int $code The ID code of the error message
+ * @param string $text The array-key of the error message in the lang file
+ * or the full string (will be detected by the function
+ * @param string $param The $a param for the error message in the lang file
+ * @return string $text The text of the error message
+ */
+function mnet_server_fault($code, $text, $param = null) {
+ global $MNET_REMOTE_CLIENT;
+ if (!is_numeric($code)) {
+ $code = 0;
+ }
+ $code = intval($code);
+
+ $string = get_string($text, 'mnet', $param);
+ if (strpos($string, '[[') === 0) {
+ $string = $text;
+ }
+
+ return mnet_server_fault_xml($code, $string);
+}
+
+/**
+ * Return the proper XML-RPC content to report an error.
+ *
+ * @param int $code The ID code of the error message
+ * @param string $text The error message
+ * @param resource $privatekey The private key that should be used to sign the response
+ * @return string $text The XML text of the error message
+ */
+function mnet_server_fault_xml($code, $text, $privatekey = null) {
+ global $MNET_REMOTE_CLIENT, $CFG;
+ // Replace illegal XML chars - is this already in a lib somewhere?
+ $text = str_replace(array('<','>','&','"',"'"), array('<','>','&','"','''), $text);
+
+ $return = mnet_server_prepare_response('
+
+
+
+
+
+ faultCode
+ '.$code.'
+
+
+ faultString
+ '.$text.'
+
+
+
+
+', $privatekey);
+
+ if (!empty($CFG->mnet_rpcdebug)) {
+ trigger_error("XMLRPC Error Response $code: $text");
+ trigger_error(print_r($return,1));
+ }
+
+ return $return;
+}
+
+
+/**
+ * Package a response in any required envelope, and return it to the client
+ *
+ * @param string $response The XMLRPC response string
+ * @param resource $privatekey The private key to sign the response with
+ * @return string The encoded response string
+ */
+function mnet_server_prepare_response($response, $privatekey = null) {
+ global $MNET_REMOTE_CLIENT;
+
+ if ($MNET_REMOTE_CLIENT->request_was_signed) {
+ $response = mnet_sign_message($response, $privatekey);
+ }
+
+ if ($MNET_REMOTE_CLIENT->request_was_encrypted) {
+ $response = mnet_encrypt_message($response, $MNET_REMOTE_CLIENT->public_key);
+ }
+
+ return $response;
+}
+
+/**
+ * If security checks are passed, dispatch the request to the function/method
+ *
+ * The config variable 'mnet_dispatcher_mode' can be:
+ * strict: Only execute functions that are in specific files
+ * off: The default - don't execute anything
+ *
+ * @param string $payload The XML-RPC request
+ *
+ * @throws mnet_server_exception
+ *
+ * @return No return val - just echo the response
+ */
+function mnet_server_dispatch($payload) {
+ global $CFG, $MNET_REMOTE_CLIENT, $DB;
+ // xmlrpc_decode_request returns an array of parameters, and the $method
+ // variable (which is passed by reference) is instantiated with the value from
+ // the methodName tag in the xml payload
+ // xmlrpc_decode_request($xml, &$method)
+ $params = xmlrpc_decode_request($payload, $method);
+
+ // $method is something like: "mod/forum/lib.php/forum_add_instance"
+ // $params is an array of parameters. A parameter might itself be an array.
+
+ // Whitelist characters that are permitted in a method name
+ // The method name must not begin with a / - avoid absolute paths
+ // A dot character . is only allowed in the filename, i.e. something.php
+ if (0 == preg_match("@^[A-Za-z0-9]+/[A-Za-z0-9/_\.-]+(\.php/)?[A-Za-z0-9_-]+$@",$method)) {
+ throw new mnet_server_exception(713, 'nosuchfunction');
+ }
+
+ if(preg_match("/^system\./", $method)) {
+ $callstack = explode('.', $method);
+ } else {
+ $callstack = explode('/', $method);
+ // callstack will look like array('mod', 'forum', 'lib.php', 'forum_add_instance');
+ }
+
+ /**
+ * What has the site administrator chosen as his dispatcher setting?
+ * strict: Only execute functions that are in specific files
+ * off: The default - don't execute anything
+ */
+ ////////////////////////////////////// OFF
+ if (!isset($CFG->mnet_dispatcher_mode) ) {
+ set_config('mnet_dispatcher_mode', 'off');
+ throw new mnet_server_exception(704, 'nosuchservice');
+ } elseif ('off' == $CFG->mnet_dispatcher_mode) {
+ throw new mnet_server_exception(704, 'nosuchservice');
+
+ ////////////////////////////////////// SYSTEM METHODS
+ } elseif ($callstack[0] == 'system') {
+ $functionname = $callstack[1];
+ $xmlrpcserver = xmlrpc_server_create();
+
+ // register all the system methods
+ $systemmethods = array('listMethods', 'methodSignature', 'methodHelp', 'listServices', 'listFiles', 'retrieveFile', 'keyswap');
+ foreach ($systemmethods as $m) {
+ // I'm adding the canonical xmlrpc references here, however we've
+ // already forbidden that the period (.) should be allowed in the call
+ // stack, so if someone tries to access our XMLRPC in the normal way,
+ // they'll already have received a RPC server fault message.
+
+ // Maybe we should allow an easement so that regular XMLRPC clients can
+ // call our system methods, and find out what we have to offer?
+ $handler = 'mnet_system';
+ if ($m == 'keyswap') {
+ $handler = 'mnet_keyswap';
+ }
+ if ($method == 'system.' . $m || $method == 'system/' . $m) {
+ xmlrpc_server_register_method($xmlrpcserver, $method, $handler);
+ $response = xmlrpc_server_call_method($xmlrpcserver, $payload, $MNET_REMOTE_CLIENT, array("encoding" => "utf-8"));
+ $response = mnet_server_prepare_response($response);
+ echo $response;
+ xmlrpc_server_destroy($xmlrpcserver);
+ return;
+ }
+ }
+ throw new mnet_server_exception(7018, 'nosuchfunction');
+
+ //////////////////////////////////// NORMAL PLUGIN DISPATCHER
+ } else {
+ // anything else comes from some sort of plugin
+ if ($rpcrecord = $DB->get_record('mnet_rpc', array('xmlrpc_path' => $method))) {
+ $response = mnet_server_invoke_plugin_method($method, $callstack, $rpcrecord, $payload);
+ $response = mnet_server_prepare_response($response);
+ echo $response;
+ return;
+ // if the rpc record isn't found, check to see if dangerous mode is on
+ ////////////////////////////////////// DANGEROUS
+ } else if ('dangerous' == $CFG->mnet_dispatcher_mode && $MNET_REMOTE_CLIENT->plaintext_is_ok()) {
+ $functionname = array_pop($callstack);
+
+ $filename = clean_param(implode('/',$callstack), PARAM_PATH);
+ if (0 == preg_match("/php$/", $filename)) {
+ // Filename doesn't end in 'php'; possible attack?
+ // Generate error response - unable to locate function
+ throw new mnet_server_exception(7012, 'nosuchfunction');
+ }
+
+ // The call stack holds the path to any include file
+ $includefile = $CFG->dirroot.'/'.$filename;
+
+ $response = mnet_server_invoke_dangerous_method($includefile, $functionname, $method, $payload);
+ echo $response;
+ return;
+ }
+ }
+ throw new mnet_server_exception(7012, 'nosuchfunction');
+}
+
+/**
+ * Execute the system functions - mostly for introspection
+ *
+ * @param string $method XMLRPC method name, e.g. system.listMethods
+ * @param array $params Array of parameters from the XMLRPC request
+ * @param string $hostinfo Hostinfo object from the mnet_host table
+ *
+ * @throws mnet_server_exception
+ *
+ * @return mixed Response data - any kind of PHP variable
+ */
+function mnet_system($method, $params, $hostinfo) {
+ global $CFG, $DB;
+
+ if (empty($hostinfo)) return array();
+
+ $id_list = $hostinfo->id;
+ if (!empty($CFG->mnet_all_hosts_id)) {
+ $id_list .= ', '.$CFG->mnet_all_hosts_id;
+ }
+
+ if ('system.listMethods' == $method || 'system/listMethods' == $method) {
+ $query = '
+ SELECT DISTINCT
+ rpc.function_name,
+ rpc.xmlrpc_path
+ FROM
+ {mnet_host2service} h2s
+ JOIN {mnet_service2rpc} s2r ON h2s.serviceid = s2r.serviceid
+ JOIN {mnet_rpc} rpc ON s2r.rpcid = rpc.id
+ JOIN {mnet_service} svc ON svc.id = s2r.serviceid
+ WHERE
+ h2s.hostid in ('.$id_list .') AND
+ h2s.publish = 1 AND rpc.enabled = 1
+ ' . ((count($params) > 0) ? 'AND svc.name = ? ' : '') . '
+ ORDER BY
+ rpc.xmlrpc_path ASC';
+ if (count($params) > 0) {
+ $params = array($params[0]);
+ }
+ $methods = array();
+ foreach ($DB->get_records_sql($query, $params) as $result) {
+ $methods[] = $result->xmlrpc_path;
+ }
+ return $methods;
+ } elseif (in_array($method, array('system.methodSignature', 'system/methodSignature', 'system.methodHelp', 'system/methodHelp'))) {
+ $query = '
+ SELECT DISTINCT
+ rpc.function_name,
+ rpc.help,
+ rpc.profile
+ FROM
+ {mnet_host2service} h2s,
+ {mnet_service2rpc} s2r,
+ {mnet_rpc} rpc
+ WHERE
+ rpc.xmlrpc_path = ? AND
+ s2r.rpcid = rpc.id AND
+ h2s.publish = 1 AND rpc.enabled = 1 AND
+ h2s.serviceid = s2r.serviceid AND
+ h2s.hostid in ('.$id_list .')';
+ $params = array($params[0]);
+
+ if (!$result = $DB->get_record_sql($query, $params)) {
+ return false;
+ }
+ if (strpos($method, 'methodSignature') !== false) {
+ return unserialize($result->profile);
+ }
+ return $result->help;
+ } elseif ('system.listServices' == $method || 'system/listServices' == $method) {
+ $query = '
+ SELECT DISTINCT
+ s.id,
+ s.name,
+ s.apiversion,
+ h2s.publish,
+ h2s.subscribe
+ FROM
+ {mnet_host2service} h2s,
+ {mnet_service} s
+ WHERE
+ h2s.serviceid = s.id AND
+ (h2s.publish = 1 OR h2s.subscribe = 1) AND
+ h2s.hostid in ('.$id_list .')
+ ORDER BY
+ s.name ASC';
+ $params = array();
+
+ $result = $DB->get_records_sql($query, $params);
+ $services = array();
+
+ if (is_array($result)) {
+ foreach($result as $service) {
+ $services[] = array('name' => $service->name,
+ 'apiversion' => $service->apiversion,
+ 'publish' => $service->publish,
+ 'subscribe' => $service->subscribe);
+ }
+ }
+
+ return $services;
+ }
+ throw new mnet_server_exception(7019, 'nosuchfunction');
+}
+
+/**
+ * Invoke a normal style plugin method
+ * This will verify permissions first.
+ *
+ * @param string $method the full xmlrpc method that was called eg auth/mnet/auth.php/user_authorise
+ * @param array $callstack the exploded callstack
+ * @param stdclass $rpcrecord the record from mnet_rpc
+ *
+ * @return mixed the response from the invoked method
+ */
+function mnet_server_invoke_plugin_method($method, $callstack, $rpcrecord, $payload) {
+ mnet_verify_permissions($rpcrecord); // will throw exceptions
+ mnet_setup_dummy_method($method, $callstack, $rpcrecord);
+ $methodname = array_pop($callstack);
+
+ $xmlrpcserver = xmlrpc_server_create();
+ xmlrpc_server_register_method($xmlrpcserver, $method, 'mnet_server_dummy_method');
+ $response = xmlrpc_server_call_method($xmlrpcserver, $payload, $methodname, array("encoding" => "utf-8"));
+ xmlrpc_server_destroy($xmlrpcserver);
+ return $response;
+}
+
+/**
+ * Initialize the object (if necessary), execute the method or function, and
+ * return the response
+ *
+ * @param string $includefile The file that contains the object definition
+ * @param string $methodname The name of the method to execute
+ * @param string $method The full path to the method
+ * @param string $payload The XML-RPC request payload
+ * @param string $class The name of the class to instantiate (or false)
+ *
+ * @throws mnet_server_exception
+ *
+ * @return string The XML-RPC response
+ */
+function mnet_server_invoke_dangerous_method($includefile, $methodname, $method, $payload) {
+
+ if (file_exists($CFG->dirroot . $includefile)) {
+ require_once $CFG->dirroot . $includefile;
+ // $callprefix matches the rpc convention
+ // of not having a leading slash
+ $callprefix = preg_replace('!^/!', '', $includefile);
+ } else {
+ throw new mnet_server_exception(705, "nosuchfile");
+ }
+
+ if ($functionname != clean_param($functionname, PARAM_PATH)) {
+ throw new mnet_server_exception(7012, "nosuchfunction");
+ }
+
+ if (!function_exists($functionname)) {
+ throw new mnet_server_exception(7012, "nosuchfunction");
+ }
+ $xmlrpcserver = xmlrpc_server_create();
+ xmlrpc_server_register_method($xmlrpcserver, $method, 'mnet_server_dummy_method');
+ $response = xmlrpc_server_call_method($xmlrpcserver, $payload, $methodname, array("encoding" => "utf-8"));
+ xmlrpc_server_destroy($xmlrpcserver);
+ return $response;
+}
+
+
+/**
+ * Accepts a public key from a new remote host and returns the public key for
+ * this host. If 'register all hosts' is turned on, it will bootstrap a record
+ * for the remote host in the mnet_host table (if it's not already there)
+ *
+ * @param string $function XML-RPC requires this but we don't... discard!
+ * @param array $params Array of parameters
+ * $params[0] is the remote wwwroot
+ * $params[1] is the remote public key
+ * @return string The XML-RPC response
+ */
+function mnet_keyswap($function, $params) {
+ global $CFG, $MNET;
+ $return = array();
+
+ if (!empty($CFG->mnet_register_allhosts)) {
+ $mnet_peer = new mnet_peer();
+ @list($wwwroot, $pubkey, $application) = each($params);
+ $keyok = $mnet_peer->bootstrap($wwwroot, $pubkey, $application);
+ if ($keyok) {
+ $mnet_peer->commit();
+ }
+ }
+ return $MNET->public_key;
+}
+
+/**
+ * Verify that the requested xmlrpc method can be called
+ * This just checks the method exists in the rpc table and is enabled.
+ *
+ * @param stdclass $rpcrecord the record from mnet_rpc
+ *
+ * @throws mnet_server_exception
+ */
+function mnet_verify_permissions($rpcrecord) {
+ global $CFG, $MNET_REMOTE_CLIENT, $DB;
+
+ $id_list = $MNET_REMOTE_CLIENT->id;
+ if (!empty($CFG->mnet_all_hosts_id)) {
+ $id_list .= ', '.$CFG->mnet_all_hosts_id;
+ }
+
+ $sql = "SELECT
+ r.*, h2s.publish
+ FROM
+ {mnet_rpc} r
+ JOIN {mnet_service2rpc} s2r ON s2r.rpcid = r.id
+ LEFT JOIN {mnet_host2service} h2s ON h2s.serviceid = s2r.serviceid
+ WHERE
+ r.id = ? AND
+ h2s.hostid in ($id_list)";
+
+ $params = array($rpcrecord->id);
+
+ if (!$permission = $DB->get_record_sql($sql, $params)) {
+ throw new mnet_server_exception(7012, "nosuchfunction");
+ } else if (!$permission->publish || !$permission->enabled) {
+ throw new mnet_server_exception(707, "nosuchfunction");
+ }
+}
+
+/**
+ * Figure out exactly what needs to be called and stashes it in $MNET_REMOTE_CLIENT
+ * Does some further verification that the method is callable
+ *
+ * @param string $method the full xmlrpc method that was called eg auth/mnet/auth.php/user_authorise
+ * @param array $callstack the exploded callstack
+ * @param stdclass $rpcrecord the record from mnet_rpc
+ *
+ * @throws mnet_server_exception
+ */
+function mnet_setup_dummy_method($method, $callstack, $rpcrecord) {
+ global $MNET_REMOTE_CLIENT, $CFG;
+ // verify that the callpath in the stack matches our records
+ // callstack will look like array('mod', 'forum', 'lib.php', 'forum_add_instance');
+ $path = get_plugin_directory($rpcrecord->plugintype, $rpcrecord->pluginname, false);
+ array_pop($callstack);
+ $providedpath = implode('/', $callstack);
+ if ($providedpath != $path . '/' . $rpcrecord->filename) {
+ throw new mnet_server_exception(705, "nosuchfile");
+ }
+ if (!file_exists($CFG->dirroot . '/' . $providedpath)) {
+ throw new mnet_server_exception(705, "nosuchfile");
+ }
+ require_once($CFG->dirroot . '/' . $providedpath);
+ if (!empty($rpcrecord->classname)) {
+ if (!class_exists($rpcrecord->classname)) {
+ throw new mnet_server_exception(708, 'nosuchclass');
+ }
+ if (!$rpcrecord->static) {
+ try {
+ $object = new $rpcrecord->classname;
+ } catch (Exception $e) {
+ throw new mnet_server_exception(709, "classerror");
+ }
+ if (!is_callable(array($object, $rpcrecord->function_name))) {
+ throw new mnet_server_exception(706, "nosuchfunction");
+ }
+ $MNET_REMOTE_CLIENT->object_to_call($object);
+ } else {
+ if (!is_callable(array($rpcrecord->classname, $rpcrecord->function_name))) {
+ throw new mnet_server_exception(706, "nosuchfunction");
+ }
+ $MNET_REMOTE_CLIENT->static_location($rpcrecord->classname);
+ }
+ }
+}
+
+/**
+ * Dummy function for the XML-RPC dispatcher - use to call a method on an object
+ * or to call a function
+ *
+ * Translate XML-RPC's strange function call syntax into a more straightforward
+ * PHP-friendly alternative. This dummy function will be called by the
+ * dispatcher, and can be used to call a method on an object, or just a function
+ *
+ * The methodName argument (eg. mnet/testlib/mnet_concatenate_strings)
+ * is ignored.
+ *
+ * @throws mnet_server_exception
+ *
+ * @param string $methodname We discard this - see 'functionname'
+ * @param array $argsarray Each element is an argument to the real
+ * function
+ * @param string $functionname The name of the PHP function you want to call
+ * @return mixed The return value will be that of the real
+ * function, whatever it may be.
+ */
+function mnet_server_dummy_method($methodname, $argsarray, $functionname) {
+ global $MNET_REMOTE_CLIENT;
+
+ try {
+ if (is_object($MNET_REMOTE_CLIENT->object_to_call)) {
+ return @call_user_func_array(array($MNET_REMOTE_CLIENT->object_to_call,$functionname), $argsarray);
+ } else if (!empty($MNET_REMOTE_CLIENT->static_location)) {
+ return @call_user_func_array(array($MNET_REMOTE_CLIENT->static_location, $functionname), $argsarray);
+ } else {
+ return @call_user_func_array($functionname, $argsarray);
+ }
+ } catch (Exception $e) {
+ exit(mnet_server_fault($e->getCode(), $e->getMessage()));
+ }
+}
+/**
+ * mnet server exception. extends moodle_exception, but takes slightly different arguments.
+ * error strings are always in mnet, so $module is not necessary,
+ * and unlike the rest of moodle, the actual int error code is used.
+ * this exception should only be used during an xmlrpc server request, ie, not for client requests.
+ */
+class mnet_server_exception extends moodle_exception {
+
+ /**
+ * @param int $intcode the numerical error associated with this fault. this is not the string errorcode
+ * @param string $languagekey the key to the language string for the error message, or the text of the message (mnet_server_fault figures it out for you) if you're not using mnet error string file
+ * @param mixed $a params for get_string
+ */
+ public function __construct($intcode, $languagekey, $a=null) {
+ parent::__construct($languagekey, 'mnet', '', $a);
+ $this->code = $intcode;
+ $this->message = $languagekey; // override this because mnet_server_fault (our handler) uses this directly
+
+ }
+}
+
diff --git a/portfolio/mahara/db/mnet.php b/portfolio/mahara/db/mnet.php
new file mode 100644
index 00000000000..1e7ba596d17
--- /dev/null
+++ b/portfolio/mahara/db/mnet.php
@@ -0,0 +1,38 @@
+.
+
+
+/**
+ * This file contains the mnet services for the mahara portfolio plugin
+ *
+ * @since 2.0
+ * @package moodlecore
+ * @subpackage portfolio
+ * @copyright 2010 Penny Leach
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$publishes = array(
+ 'pf' => array(
+ 'apiversion' => 1,
+ 'classname' => 'portfolio_plugin_mahara',
+ 'filename' => 'lib.php',
+ 'methods' => array(
+ 'fetch_file'
+ ),
+ ),
+);
+
diff --git a/repository/remotemoodle/db/mnet.php b/repository/remotemoodle/db/mnet.php
new file mode 100644
index 00000000000..53727c7ca2c
--- /dev/null
+++ b/repository/remotemoodle/db/mnet.php
@@ -0,0 +1,39 @@
+.
+
+
+/**
+ * This file contains the mnet services for the remotemoodle repository plugin
+ *
+ * @since 2.0
+ * @package moodlecore
+ * @subpackage repository
+ * @copyright 2010 Penny Leach
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$publishes = array(
+ 'remoterep' => array(
+ 'apiversion' => 1,
+ 'classname' => 'repository_remotemoodle',
+ 'filename' => 'repository.class.php',
+ 'methods' => array(
+ 'getFileList',
+ 'retrieveFile',
+ ),
+ ),
+);