Example #1
0
/**
 * 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, $DB;
    $remoteclient = get_mnet_remote_client();
    // 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, $remoteclient, 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('xmlrpcpath' => $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 && $remoteclient->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');
}
Example #2
0
/**
 * 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
 * @return                     No return val - just echo the response
 */
function mnet_server_dispatch($payload)
{
    global $CFG, $MNET_REMOTE_CLIENT;
    // 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)) {
        exit(mnet_server_fault(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');
        exit(mnet_server_fault(704, 'nosuchservice'));
    } elseif ('off' == $CFG->mnet_dispatcher_mode) {
        exit(mnet_server_fault(704, 'nosuchservice'));
        ////////////////////////////////////// SYSTEM METHODS
    } elseif ($callstack[0] == 'system') {
        $functionname = $callstack[1];
        $xmlrpcserver = xmlrpc_server_create();
        // 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?
        xmlrpc_server_register_method($xmlrpcserver, 'system.listMethods', 'mnet_system');
        xmlrpc_server_register_method($xmlrpcserver, 'system/listMethods', 'mnet_system');
        xmlrpc_server_register_method($xmlrpcserver, 'system.methodSignature', 'mnet_system');
        xmlrpc_server_register_method($xmlrpcserver, 'system/methodSignature', 'mnet_system');
        xmlrpc_server_register_method($xmlrpcserver, 'system.methodHelp', 'mnet_system');
        xmlrpc_server_register_method($xmlrpcserver, 'system/methodHelp', 'mnet_system');
        xmlrpc_server_register_method($xmlrpcserver, 'system.listServices', 'mnet_system');
        xmlrpc_server_register_method($xmlrpcserver, 'system/listServices', 'mnet_system');
        xmlrpc_server_register_method($xmlrpcserver, 'system.keyswap', 'mnet_keyswap');
        xmlrpc_server_register_method($xmlrpcserver, 'system/keyswap', 'mnet_keyswap');
        if ($method == 'system.listMethods' || $method == 'system/listMethods' || $method == 'system.methodSignature' || $method == 'system/methodSignature' || $method == 'system.methodHelp' || $method == 'system/methodHelp' || $method == 'system.listServices' || $method == 'system/listServices' || $method == 'system.keyswap' || $method == 'system/keyswap') {
            $response = xmlrpc_server_call_method($xmlrpcserver, $payload, $MNET_REMOTE_CLIENT, array("encoding" => "utf-8"));
            $response = mnet_server_prepare_response($response);
        } else {
            exit(mnet_server_fault(7018, 'nosuchfunction'));
        }
        xmlrpc_server_destroy($xmlrpcserver);
        echo $response;
        ////////////////////////////////////// STRICT AUTH
    } elseif ($callstack[0] == 'auth') {
        // Break out the callstack into its elements
        list($base, $plugin, $filename, $methodname) = $callstack;
        // We refuse to include anything that is not auth.php
        if ($filename == 'auth.php' && is_enabled_auth($plugin)) {
            $authclass = 'auth_plugin_' . $plugin;
            $includefile = '/auth/' . $plugin . '/auth.php';
            $response = mnet_server_invoke_method($includefile, $methodname, $method, $payload, $authclass);
            $response = mnet_server_prepare_response($response);
            echo $response;
        } else {
            // Generate error response - unable to locate function
            exit(mnet_server_fault(702, 'nosuchfunction'));
        }
        ////////////////////////////////////// STRICT ENROL
    } elseif ($callstack[0] == 'enrol') {
        // Break out the callstack into its elements
        list($base, $plugin, $filename, $methodname) = $callstack;
        if ($filename == 'enrol.php' && is_enabled_enrol($plugin)) {
            $enrolclass = 'enrolment_plugin_' . $plugin;
            $includefile = '/enrol/' . $plugin . '/enrol.php';
            $response = mnet_server_invoke_method($includefile, $methodname, $method, $payload, $enrolclass);
            $response = mnet_server_prepare_response($response);
            echo $response;
        } else {
            // Generate error response - unable to locate function
            exit(mnet_server_fault(703, 'nosuchfunction'));
        }
        ////////////////////////////////////// STRICT MOD/*
    } elseif ($callstack[0] == 'mod' || 'dangerous' == $CFG->mnet_dispatcher_mode) {
        list($base, $module, $filename, $functionname) = $callstack;
        ////////////////////////////////////// STRICT MOD/*
        if ($base == 'mod' && $filename == 'rpclib.php') {
            $includefile = '/mod/' . $module . '/rpclib.php';
            $response = mnet_server_invoke_method($includefile, $functionname, $method, $payload);
            $response = mnet_server_prepare_response($response);
            echo $response;
            ////////////////////////////////////// DANGEROUS
        } elseif ('dangerous' == $CFG->mnet_dispatcher_mode && $MNET_REMOTE_CLIENT->plaintext_is_ok()) {
            $functionname = array_pop($callstack);
            if ($MNET_REMOTE_CLIENT->plaintext_is_ok()) {
                $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
                    exit(mnet_server_fault(7012, 'nosuchfunction'));
                }
                // The call stack holds the path to any include file
                $includefile = $CFG->dirroot . '/' . $filename;
                $response = mnet_server_invoke_method($includefile, $functionname, $method, $payload);
                echo $response;
            }
        } else {
            // Generate error response - unable to locate function
            exit(mnet_server_fault(7012, 'nosuchfunction'));
        }
    } else {
        // Generate error response - unable to locate function
        exit(mnet_server_fault(7012, 'nosuchfunction'));
    }
}