public function get_content() { global $CFG, $USER, $OUTPUT; if (has_capability('block/papercut:view', $this->context)) { $this->content = new stdClass(); $this->content->footer = ''; $this->content->items = array(); $this->content->icons = array(); $serverip = explode('.', $_SERVER['SERVER_ADDR']); $internal = address_in_subnet(getremoteaddr(), $serverip[0] . '.' . $serverip[1]); $strnobalance = get_string('nobalance', 'block_papercut'); $image = $OUTPUT->pix_icon('balance_not_available', $strnobalance, 'block_papercut'); $http = $CFG->block_papercut_https ? 'https://' : 'http://'; $serverurl = $http . $CFG->block_papercut_server_url . ':' . $CFG->block_papercut_server_port; $scriptattrs = array('type' => 'text/javascript'); $wisgetsattrs = $scriptattrs; $widgetsattrs['src'] = $serverurl . '/content/widgets/widgets.js'; $script1 = "var pcUsername = '******';" . "var pcServerURL = '{$serverurl}'; pcGetUserDetails();"; $script2 = "pcInitUserEnvironmentalImpactWidget('widgetEnvironment');" . "pcInitUserBalanceWidget('widgetBalance');"; if ($internal) { $this->content->text .= html_writer::tag('script', '', $widgetsattrs); } $this->content->text .= html_writer::tag('script', $script1, $scriptattrs); $this->content->text .= html_writer::tag('div', $image, array('id' => 'widgetBalance')); $this->content->text .= html_writer::tag('div', '', array('id' => 'widgetEnvironment')); if ($internal) { $this->content->text .= html_writer::tag('script', $script2, $scriptattrs); } return $this->content; } }
function test_address_in_subnet() { $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.1')); $this->assertFalse(address_in_subnet('123.121.234.2', '123.121.234.1')); $this->assertFalse(address_in_subnet('123.121.134.1', '123.121.234.1')); $this->assertFalse(address_in_subnet('113.121.234.1', '123.121.234.1')); $this->assertTrue(address_in_subnet('123.121.234.0', '123.121.234.2/28')); $this->assertTrue(address_in_subnet('123.121.234.15', '123.121.234.2/28')); $this->assertFalse(address_in_subnet('123.121.234.16', '123.121.234.2/28')); $this->assertFalse(address_in_subnet('123.121.234.255', '123.121.234.2/28')); $this->assertFalse(address_in_subnet('123.121.234.0', '123.121.234.0/')); $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.0/')); $this->assertTrue(address_in_subnet('232.232.232.232', '123.121.234.0/0')); $this->assertFalse(address_in_subnet('123.122.234.1', '123.121.')); $this->assertFalse(address_in_subnet('223.121.234.1', '123.121.')); $this->assertTrue(address_in_subnet('123.121.234.1', '123.121')); $this->assertFalse(address_in_subnet('123.122.234.1', '123.121')); $this->assertFalse(address_in_subnet('223.121.234.1', '123.121')); $this->assertFalse(address_in_subnet('123.121.234.100', '123.121.234.10')); $this->assertFalse(address_in_subnet('123.121.234.9', '123.121.234.10-20')); $this->assertTrue(address_in_subnet('123.121.234.10', '123.121.234.10-20')); $this->assertTrue(address_in_subnet('123.121.234.15', '123.121.234.10-20')); $this->assertTrue(address_in_subnet('123.121.234.20', '123.121.234.10-20')); $this->assertFalse(address_in_subnet('123.121.234.21', '123.121.234.10-20')); $this->assertTrue(address_in_subnet(' 123.121.234.1 ', ' 123.121.234.1 , 1.1.1.1/16,2.2.,3.3.3.3-6 ')); $this->assertTrue(address_in_subnet(' 1.1.2.3 ', ' 123.121.234.1 , 1.1.1.1/16,2.2.,3.3.3.3-6 ')); $this->assertTrue(address_in_subnet(' 2.2.234.1 ', ' 123.121.234.1 , 1.1.1.1/16,2.2.,3.3.3.3-6 ')); $this->assertTrue(address_in_subnet(' 3.3.3.4 ', ' 123.121.234.1 , 1.1.1.1/16,2.2.,3.3.3.3-6 ')); $this->assertFalse(address_in_subnet(' 123.121.234.2 ', ' 123.121.234.1 , 1.1.1.1/16,2.2.,3.3.3.3-6 ')); $this->assertFalse(address_in_subnet(' 2.1.2.3 ', ' 123.121.234.1 , 1.1.1.1/16,2.2.,3.3.3.3-6 ')); $this->assertFalse(address_in_subnet(' 2.3.234.1 ', ' 123.121.234.1 , 1.1.1.1/16,2.2.,3.3.3.3-6 ')); $this->assertFalse(address_in_subnet(' 3.3.3.7 ', ' 123.121.234.1 , 1.1.1.1/16,2.2.,3.3.3.3-6 ')); $this->assertFalse(address_in_subnet('172.16.1.142', '172.16.1.143/148')); }
public function prevent_access() { if (address_in_subnet(getremoteaddr(), $this->quiz->subnet)) { return false; } else { return get_string('subnetwrong', 'quizaccess_ipaddress'); } }
function plaintext_is_ok() { global $CFG; $trusted_hosts = explode(',', get_config('mnet', 'mnet_trusted_hosts')); foreach ($trusted_hosts as $host) { if (address_in_subnet(getremoteaddr(), $host)) { return true; } } return false; }
function find_lms_user($installid, $username, $signature, $confirmaction = null, $firstname = null, $lastname = null, $email = null) { global $CFG; // find this host from the installid if (empty($CFG->lmshosts) || !is_array($CFG->lmshosts) || !array_key_exists($installid, $CFG->lmshosts)) { return LMS_NO_SUCH_HOST; } $host = $CFG->lmshosts[$installid]; // validate our md5 hash if ($confirmaction == 'signupconfirmation') { $stringtohash = $installid . '|' . $username . '|' . $firstname . '|' . $lastname . '|' . $email . '|' . $host['token']; } else { $stringtohash = $installid . '|' . $username . '|' . $host['token']; // firstname, lastname and email cannot be relied upon not to change // so we only want to add them to the hash on signup, not for auth or anything else. } $checksig = md5($stringtohash); if ($checksig != $signature) { return LMS_INVALID_HASH; } // if we have an ip address, check it. if (array_key_exists('networkaddress', $host) && empty($confirmaction)) { if (!address_in_subnet(getremoteaddr(), $host['networkaddress'])) { return LMS_INVALID_NETWORK; } } if (!empty($confirmaction) && !empty($host['confirmurl'])) { $client = new Snoopy(); $client->agent = LMS_SNOOPY_USER_AGENT; $client->read_timeout = 5; $client->use_gzip = true; $postdata = array('action' => $confirmaction, 'username' => $username, 'signature' => $signature); @$client->submit($host['confirmurl'], $postdata); if ($client->results != 'OK') { return clean_param($client->results, PARAM_CLEAN); } } // find our user (we only want to check username and installid, the others could potentially change.. if (!($user = get_record_sql('SELECT u.* FROM ' . $CFG->prefix . 'users u JOIN ' . $CFG->prefix . 'users_alias ua ON ua.user_id = u.ident WHERE ua.installid = ? AND ua.username = ?', array($installid, $username)))) { return LMS_NO_SUCH_USER; } return $user; }
/** * Will get called before the login page is shown, if NTLM SSO * is enabled, and the user is in the right network, we'll redirect * to the magic NTLM page for SSO... * */ function loginpage_hook() { global $CFG; if ($_SERVER['REQUEST_METHOD'] === 'GET' && !empty($this->config->ntlmsso_enabled) && !empty($this->config->ntlmsso_subnet) && empty($_GET['authldap_skipntlmsso']) && (isguestuser() || !isloggedin()) && address_in_subnet($_SERVER['REMOTE_ADDR'], $this->config->ntlmsso_subnet)) { redirect("{$CFG->wwwroot}/auth/ldap/ntlmsso_attempt.php"); } }
/** * Is current ip in give list? * * @param string $list * @return bool */ function remoteip_in_list($list) { $inlist = false; $clientip = getremoteaddr(null); if (!$clientip) { // Ensure access on cli. return true; } $list = explode("\n", $list); foreach ($list as $subnet) { $subnet = trim($subnet); if (address_in_subnet($clientip, $subnet)) { $inlist = true; break; } } return $inlist; }
$session = session_get_instance(); if (!$session->session_exists($token->sid)) { //this token will never be valid anymore, delete it $DB->delete_records('external_tokens', array('sid' => $token->sid)); $unsettoken = true; } } //remove token if no valid anymore //Also delete this wrong token (similar logic to the web service servers // /webservice/lib.php/webservice_server::authenticate_by_token()) if (!empty($token->validuntil) and $token->validuntil < time()) { $DB->delete_records('external_tokens', array('token' => $token->token, 'tokentype' => EXTERNAL_TOKEN_PERMANENT)); $unsettoken = true; } // remove token if its ip not in whitelist if (isset($token->iprestriction) and !address_in_subnet(getremoteaddr(), $token->iprestriction)) { $unsettoken = true; } if ($unsettoken) { unset($tokens[$key]); } } // if some valid tokens exist then use the most recent if (count($tokens) > 0) { $token = array_pop($tokens); } else { if (has_capability('moodle/webservice:createmobiletoken', get_system_context()) or !is_siteadmin($user) && has_capability('moodle/webservice:createtoken', get_system_context())) { // if service doesn't exist, dml will throw exception $service_record = $DB->get_record('external_services', array('shortname' => $serviceshortname, 'enabled' => 1), '*', MUST_EXIST); // create a new token $token = new stdClass();
public function __authenticate($username, $password, $serviceshortname) { global $CFG, $DB; //echo $OUTPUT->header(); if (!$CFG->enablewebservices) { throw new moodle_exception('enablewsdescription', 'webservice'); } $username = trim(textlib::strtolower($username)); if (is_restored_user($username)) { throw new moodle_exception('restoredaccountresetpassword', 'webservice'); } $user = authenticate_user_login($username, $password); if (!empty($user)) { //Non admin can not authenticate if maintenance mode $hassiteconfig = has_capability('moodle/site:config', context_system::instance(), $user); if (!empty($CFG->maintenance_enabled) and !$hassiteconfig) { throw new moodle_exception('sitemaintenance', 'admin'); } if (isguestuser($user)) { throw new moodle_exception('noguest'); } if (empty($user->confirmed)) { throw new moodle_exception('usernotconfirmed', 'moodle', '', $user->username); } // check credential expiry $userauth = get_auth_plugin($user->auth); if (!empty($userauth->config->expiration) and $userauth->config->expiration == 1) { $days2expire = $userauth->password_expire($user->username); if (intval($days2expire) < 0) { throw new moodle_exception('passwordisexpired', 'webservice'); } } // let enrol plugins deal with new enrolments if necessary enrol_check_plugins($user); // setup user session to check capability session_set_user($user); //check if the service exists and is enabled $service = $DB->get_record('external_services', array('shortname' => $serviceshortname, 'enabled' => 1)); if (empty($service)) { // will throw exception if no token found throw new moodle_exception('servicenotavailable', 'webservice'); } //check if there is any required system capability if ($service->requiredcapability and !has_capability($service->requiredcapability, context_system::instance(), $user)) { throw new moodle_exception('missingrequiredcapability', 'webservice', '', $service->requiredcapability); } //specific checks related to user restricted service if ($service->restrictedusers) { $authoriseduser = $DB->get_record('external_services_users', array('externalserviceid' => $service->id, 'userid' => $user->id)); if (empty($authoriseduser)) { throw new moodle_exception('usernotallowed', 'webservice', '', $serviceshortname); } if (!empty($authoriseduser->validuntil) and $authoriseduser->validuntil < time()) { throw new moodle_exception('invalidtimedtoken', 'webservice'); } if (!empty($authoriseduser->iprestriction) and !address_in_subnet(getremoteaddr(), $authoriseduser->iprestriction)) { throw new moodle_exception('invalidiptoken', 'webservice'); } } //Check if a token has already been created for this user and this service //Note: this could be an admin created or an user created token. // It does not really matter we take the first one that is valid. $tokenssql = "SELECT t.id, t.sid, t.token, t.validuntil, t.iprestriction\n FROM {external_tokens} t\n WHERE t.userid = ? AND t.externalserviceid = ? AND t.tokentype = ?\n ORDER BY t.timecreated ASC"; $tokens = $DB->get_records_sql($tokenssql, array($user->id, $service->id, EXTERNAL_TOKEN_PERMANENT)); //A bit of sanity checks foreach ($tokens as $key => $token) { /// Checks related to a specific token. (script execution continue) $unsettoken = false; //if sid is set then there must be a valid associated session no matter the token type if (!empty($token->sid)) { $session = session_get_instance(); if (!$session->session_exists($token->sid)) { //this token will never be valid anymore, delete it $DB->delete_records('external_tokens', array('sid' => $token->sid)); $unsettoken = true; } } //remove token if no valid anymore //Also delete this wrong token (similar logic to the web service servers // /webservice/lib.php/webservice_server::authenticate_by_token()) if (!empty($token->validuntil) and $token->validuntil < time()) { $DB->delete_records('external_tokens', array('token' => $token->token, 'tokentype' => EXTERNAL_TOKEN_PERMANENT)); $unsettoken = true; } // remove token if its ip not in whitelist if (isset($token->iprestriction) and !address_in_subnet(getremoteaddr(), $token->iprestriction)) { $unsettoken = true; } if ($unsettoken) { unset($tokens[$key]); } } // if some valid tokens exist then use the most recent if (count($tokens) > 0) { $token = array_pop($tokens); } else { if ($serviceshortname == MOODLE_OFFICIAL_MOBILE_SERVICE and has_capability('moodle/webservice:createmobiletoken', get_system_context()) or !is_siteadmin($user) && has_capability('moodle/webservice:createtoken', get_system_context())) { // if service doesn't exist, dml will throw exception $service_record = $DB->get_record('external_services', array('shortname' => $serviceshortname, 'enabled' => 1), '*', MUST_EXIST); // create a new token $token = new stdClass(); $token->token = md5(uniqid(rand(), 1)); $token->userid = $user->id; $token->tokentype = EXTERNAL_TOKEN_PERMANENT; $token->contextid = context_system::instance()->id; $token->creatorid = $user->id; $token->timecreated = time(); $token->externalserviceid = $service_record->id; $tokenid = $DB->insert_record('external_tokens', $token); add_to_log(SITEID, 'webservice', 'automatically create user token', '', 'User ID: ' . $user->id); $token->id = $tokenid; } else { throw new moodle_exception('cannotcreatetoken', 'webservice', '', $serviceshortname); } } // log token access $DB->set_field('external_tokens', 'lastaccess', time(), array('id' => $token->id)); add_to_log(SITEID, 'webservice', 'sending requested user token', '', 'User ID: ' . $user->id); $usertoken = new stdClass(); $usertoken->token = $token->token; //complete login process by activating session. // To restrict the admin user to login into application if (is_siteadmin($user)) { $heIsAdmin = new stdClass(); $heIsAdmin->error = 'admin_user'; echo json_encode($heIsAdmin); die; } Login::__app_complete_user_login($user); $forcePasswordChangesql = "SELECT up.userid\n FROM {user_preferences} up\n WHERE up.userid = ? AND up.name = ? AND up.value = ?"; $forcePasswordChange = $DB->get_records_sql($forcePasswordChangesql, array($user->id, 'auth_forcepasswordchange', 1)); //User Update Profile starts here $admins = get_admins(); $currentAdmin = end($admins); $admintokensql = "SELECT et.token\n FROM {external_tokens} et\n WHERE et.userid = ?"; $currrentAdminToken = $DB->get_records_sql($admintokensql, array($currentAdmin->id), 0, 1); $unique_key = substr(md5(mt_rand(0, 1000000)), 0, 7); $keys = array_keys($currrentAdminToken); $appuser = new stdClass(); $user->token = $token->token; $user->forcePasswordChange = !empty($forcePasswordChange) ? true : false; $user->updateProfile = substr($unique_key, 0, 3) . $keys[0] . substr($unique_key, 3, 7); //Get User role $rolesql = "SELECT id\n FROM {role} \n WHERE shortname = ?"; $roleid = array_values($DB->get_records_sql($rolesql, array('reportuser'))); $reportuser = array_values($DB->get_records_sql("SELECT id FROM {role_assignments} WHERE roleid=" . $roleid[0]->id . " AND userid=" . $user->id . "")); if ($reportuser[0]->id != '') { $user->role = 'reportuser'; } else { $user->role = ''; } //User Update Profile ends here unset($user->password); $appuser->USER = $user; $user->country_value = $user->country; $user->country = get_string($user->country, 'countries'); echo json_encode($appuser); } else { throw new moodle_exception('usernamenotfound', 'moodle'); } }
/** * Load the virtual class needed for the web service. * * Initialises the virtual class that contains the web service functions that the user is allowed to use. * The web service function will be available if the user: * - is validly registered in the external_services_users table. * - has the required capability. * - meets the IP restriction requirement. * This virtual class can be used by web service protocols such as SOAP, especially when generating WSDL. * NOTE: The implementation of this method has been mostly copied from webservice_zend_server::init_server_class(). */ protected function init_service_class() { global $USER, $DB; // Initialise service methods and struct classes. $this->servicemethods = array(); $this->servicestructs = array(); $params = array(); $wscond1 = ''; $wscond2 = ''; if ($this->restricted_serviceid) { $params = array('sid1' => $this->restricted_serviceid, 'sid2' => $this->restricted_serviceid); $wscond1 = 'AND s.id = :sid1'; $wscond2 = 'AND s.id = :sid2'; } $sql = "SELECT s.*, NULL AS iprestriction\n FROM {external_services} s\n JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 0)\n WHERE s.enabled = 1 {$wscond1}\n\n UNION\n\n SELECT s.*, su.iprestriction\n FROM {external_services} s\n JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 1)\n JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = :userid)\n WHERE s.enabled = 1 AND (su.validuntil IS NULL OR su.validuntil < :now) {$wscond2}"; $params = array_merge($params, array('userid' => $USER->id, 'now' => time())); $serviceids = array(); $remoteaddr = getremoteaddr(); // Query list of external services for the user. $rs = $DB->get_recordset_sql($sql, $params); // Check which service ID to include. foreach ($rs as $service) { if (isset($serviceids[$service->id])) { continue; // Service already added. } if ($service->requiredcapability and !has_capability($service->requiredcapability, $this->restricted_context)) { continue; // Cap required, sorry. } if ($service->iprestriction and !address_in_subnet($remoteaddr, $service->iprestriction)) { continue; // Wrong request source ip, sorry. } $serviceids[$service->id] = $service->id; } $rs->close(); // Generate the virtual class name. $classname = 'webservices_virtual_class_000000'; while (class_exists($classname)) { $classname++; } $this->serviceclass = $classname; // Get the list of all available external functions. $wsmanager = new webservice(); $functions = $wsmanager->get_external_functions($serviceids); // Generate code for the virtual methods for this web service. $methods = ''; foreach ($functions as $function) { $methods .= $this->get_virtual_method_code($function); } $code = <<<EOD /** * Virtual class web services for user id {$USER->id} in context {$this->restricted_context->id}. */ class {$classname} { {$methods} } EOD; // Load the virtual class definition into memory. eval($code); }
/** * Fetches the function description from database, * verifies user is allowed to use this function and * loads all paremeters and return descriptions. * @return void */ protected function load_function_info() { global $DB, $USER, $CFG; if (empty($this->functionname)) { throw new invalid_parameter_exception('Missing function name'); } // function must exist $function = external_function_info($this->functionname); if ($this->restricted_serviceid) { $params = array('sid1' => $this->restricted_serviceid, 'sid2' => $this->restricted_serviceid); $wscond1 = 'AND s.id = :sid1'; $wscond2 = 'AND s.id = :sid2'; } else { $params = array(); $wscond1 = ''; $wscond2 = ''; } // now let's verify access control // now make sure the function is listed in at least one service user is allowed to use // allow access only if: // 1/ entry in the external_services_users table if required // 2/ validuntil not reached // 3/ has capability if specified in service desc // 4/ iprestriction $sql = "SELECT s.*, NULL AS iprestriction\n FROM {external_services} s\n JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 0 AND sf.functionname = :name1)\n WHERE s.enabled = 1 {$wscond1}\n\n UNION\n\n SELECT s.*, su.iprestriction\n FROM {external_services} s\n JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 1 AND sf.functionname = :name2)\n JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = :userid)\n WHERE s.enabled = 1 AND su.validuntil IS NULL OR su.validuntil < :now {$wscond2}"; $params = array_merge($params, array('userid' => $USER->id, 'name1' => $function->name, 'name2' => $function->name, 'now' => time())); $rs = $DB->get_recordset_sql($sql, $params); // now make sure user may access at least one service $remoteaddr = getremoteaddr(); $allowed = false; foreach ($rs as $service) { if ($service->requiredcapability and !has_capability($service->requiredcapability, $this->restricted_context)) { continue; // cap required, sorry } if ($service->iprestriction and !address_in_subnet($remoteaddr, $service->iprestriction)) { continue; // wrong request source ip, sorry } $allowed = true; break; // one service is enough, no need to continue } $rs->close(); if (!$allowed) { throw new webservice_access_exception('Access to external function not allowed'); } // we have all we need now $this->function = $function; }
/** * require_subnet * * @return xxx */ function require_subnet() { if (!$this->subnet) { return false; } if (address_in_subnet(getremoteaddr(), $this->subnet)) { return false; } // user's IP address is missing or does not match required subnet mask return get_string('subnetwrong', 'quiz'); }
/** * Fetches the function description from database, * verifies user is allowed to use this function and * loads all paremeters and return descriptions. * @return void */ protected function load_function_info() { global $USER; if (empty($this->functionname)) { throw new WebserviceInvalidParameterException(get_string('missingfuncname', 'webserivce')); } // function must exist $function = webservice_function_info($this->functionname); if (!$function) { throw new WebserviceAccessException(get_string('accessextfunctionnotconf', 'auth.webservice')); } // first ofall get a complete list of services user is allowed to access if ($this->restricted_serviceid) { $wscond1 = 'AND s.id = ? '; $wscond2 = 'AND s.id = ? '; } else { $wscond1 = ''; $wscond2 = ''; } // now let's verify access control // now make sure the function is listed in at least one service user is allowed to use // allow access only if: // 1/ entry in the external_services_users table if required // 2/ validuntil not reached // 3/ has capability if specified in service desc // 4/ iprestriction $sql = "SELECT s.*, NULL AS iprestriction\n FROM {external_services} s\n JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND (s.restrictedusers = ? OR s.tokenusers = ?) AND sf.functionname = ?)\n WHERE s.enabled = ? {$wscond1}\n\n UNION\n\n SELECT s.*, su.iprestriction\n FROM {external_services} s\n JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = ? AND sf.functionname = ?)\n JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = ?)\n WHERE s.enabled = ? AND su.validuntil IS NULL OR su.validuntil < ? {$wscond2}"; $params = array(0, 1, $function->name, 1); $wscond1 && ($params[] = $this->restricted_serviceid); $params[] = 1; $params[] = $function->name; $params[] = $USER->get('id'); $params[] = 1; $params[] = time(); $wscond2 && ($params[] = $this->restricted_serviceid); $rs = get_recordset_sql($sql, $params); // now make sure user may access at least one service $remoteaddr = getremoteaddr(); $allowed = false; $serviceids = array(); foreach ($rs as $service) { $serviceids[] = $service['id']; if ($service['iprestriction'] and !address_in_subnet($remoteaddr, $service['iprestriction'])) { // wrong request source ip, sorry continue; } $allowed = true; // one service is enough, no need to continue break; } $rs->close(); if (!$allowed) { throw new WebserviceAccessException(get_string('accesstofunctionnotallowed', 'auth.webservice', $this->functionname)); } // now get the list of all functions - this triggers the stashing of // functions in the context $wsmanager = new webservice(); $functions = $wsmanager->get_external_functions($serviceids); // we have all we need now $this->function = $function; }
/** * Generate or return an existing token for the current authenticated user. * This function is used for creating a valid token for users authenticathing via login/token.php or admin/tool/mobile/launch.php. * * @param stdClass $service external service object * @return stdClass token object * @since Moodle 3.2 * @throws moodle_exception */ function external_generate_token_for_current_user($service) { global $DB, $USER; core_user::require_active_user($USER, true, true); // Check if there is any required system capability. if ($service->requiredcapability and !has_capability($service->requiredcapability, context_system::instance())) { throw new moodle_exception('missingrequiredcapability', 'webservice', '', $service->requiredcapability); } // Specific checks related to user restricted service. if ($service->restrictedusers) { $authoriseduser = $DB->get_record('external_services_users', array('externalserviceid' => $service->id, 'userid' => $USER->id)); if (empty($authoriseduser)) { throw new moodle_exception('usernotallowed', 'webservice', '', $service->shortname); } if (!empty($authoriseduser->validuntil) and $authoriseduser->validuntil < time()) { throw new moodle_exception('invalidtimedtoken', 'webservice'); } if (!empty($authoriseduser->iprestriction) and !address_in_subnet(getremoteaddr(), $authoriseduser->iprestriction)) { throw new moodle_exception('invalidiptoken', 'webservice'); } } // Check if a token has already been created for this user and this service. $conditions = array('userid' => $USER->id, 'externalserviceid' => $service->id, 'tokentype' => EXTERNAL_TOKEN_PERMANENT); $tokens = $DB->get_records('external_tokens', $conditions, 'timecreated ASC'); // A bit of sanity checks. foreach ($tokens as $key => $token) { // Checks related to a specific token. (script execution continue). $unsettoken = false; // If sid is set then there must be a valid associated session no matter the token type. if (!empty($token->sid)) { if (!\core\session\manager::session_exists($token->sid)) { // This token will never be valid anymore, delete it. $DB->delete_records('external_tokens', array('sid' => $token->sid)); $unsettoken = true; } } // Remove token is not valid anymore. if (!empty($token->validuntil) and $token->validuntil < time()) { $DB->delete_records('external_tokens', array('token' => $token->token, 'tokentype' => EXTERNAL_TOKEN_PERMANENT)); $unsettoken = true; } // Remove token if its ip not in whitelist. if (isset($token->iprestriction) and !address_in_subnet(getremoteaddr(), $token->iprestriction)) { $unsettoken = true; } if ($unsettoken) { unset($tokens[$key]); } } // If some valid tokens exist then use the most recent. if (count($tokens) > 0) { $token = array_pop($tokens); } else { $context = context_system::instance(); $isofficialservice = $service->shortname == MOODLE_OFFICIAL_MOBILE_SERVICE; if ($isofficialservice and has_capability('moodle/webservice:createmobiletoken', $context) or !is_siteadmin($USER) && has_capability('moodle/webservice:createtoken', $context)) { // Create a new token. $token = new stdClass(); $token->token = md5(uniqid(rand(), 1)); $token->userid = $USER->id; $token->tokentype = EXTERNAL_TOKEN_PERMANENT; $token->contextid = context_system::instance()->id; $token->creatorid = $USER->id; $token->timecreated = time(); $token->externalserviceid = $service->id; // MDL-43119 Token valid for 3 months (12 weeks). $token->validuntil = $token->timecreated + 12 * WEEKSECS; $token->iprestriction = null; $token->sid = null; $token->lastaccess = null; // Generate the private token, it must be transmitted only via https. $token->privatetoken = random_string(64); $token->id = $DB->insert_record('external_tokens', $token); $eventtoken = clone $token; $eventtoken->privatetoken = null; $params = array('objectid' => $eventtoken->id, 'relateduserid' => $USER->id, 'other' => array('auto' => true)); $event = \core\event\webservice_token_created::create($params); $event->add_record_snapshot('external_tokens', $eventtoken); $event->trigger(); } else { throw new moodle_exception('cannotcreatetoken', 'webservice', '', $service->shortname); } } return $token; }
/** * Fetches the function description from database, * verifies user is allowed to use this function and * loads all paremeters and return descriptions. */ protected function load_function_info() { global $DB, $USER, $CFG; if (empty($this->functionname)) { throw new invalid_parameter_exception('Missing function name'); } // function must exist $function = external_function_info($this->functionname); if ($this->restricted_serviceid) { $params = array('sid1' => $this->restricted_serviceid, 'sid2' => $this->restricted_serviceid); $wscond1 = 'AND s.id = :sid1'; $wscond2 = 'AND s.id = :sid2'; } else { $params = array(); $wscond1 = ''; $wscond2 = ''; } // now let's verify access control // now make sure the function is listed in at least one service user is allowed to use // allow access only if: // 1/ entry in the external_services_users table if required // 2/ validuntil not reached // 3/ has capability if specified in service desc // 4/ iprestriction $sql = "SELECT s.*, NULL AS iprestriction\n FROM {external_services} s\n JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 0 AND sf.functionname = :name1)\n WHERE s.enabled = 1 {$wscond1}\n\n UNION\n\n SELECT s.*, su.iprestriction\n FROM {external_services} s\n JOIN {external_services_functions} sf ON (sf.externalserviceid = s.id AND s.restrictedusers = 1 AND sf.functionname = :name2)\n JOIN {external_services_users} su ON (su.externalserviceid = s.id AND su.userid = :userid)\n WHERE s.enabled = 1 AND (su.validuntil IS NULL OR su.validuntil < :now) {$wscond2}"; $params = array_merge($params, array('userid' => $USER->id, 'name1' => $function->name, 'name2' => $function->name, 'now' => time())); $rs = $DB->get_recordset_sql($sql, $params); // now make sure user may access at least one service $remoteaddr = getremoteaddr(); $allowed = false; foreach ($rs as $service) { if ($service->requiredcapability and !has_capability($service->requiredcapability, $this->restricted_context)) { continue; // cap required, sorry } if ($service->iprestriction and !address_in_subnet($remoteaddr, $service->iprestriction)) { continue; // wrong request source ip, sorry } $allowed = true; break; // one service is enough, no need to continue } $rs->close(); if (!$allowed) { throw new webservice_access_exception('Access to the function ' . $this->functionname . '() is not allowed. There could be multiple reasons for this: 1. The service linked to the user token does not contain the function. 2. The service is user-restricted and the user is not listed. 3. The service is IP-restricted and the user IP is not listed. 4. The service is time-restricted and the time has expired. 5. The token is time-restricted and the time has expired. 6. The service requires a specific capability which the user does not have. 7. The function is called with username/password (no user token is sent) and none of the services has the function to allow the user. These settings can be found in Administration > Site administration > Plugins > Web services > External services and Manage tokens.'); } // we have all we need now $this->function = $function; }
$navigation = build_navigation('', $cm); $button = update_module_button($cm->id, $course->id, get_string("modulename", "hotpot")); $button = '<div style="font-size:0.75em;">' . $button . '</div>'; $loggedinas = '<span class="logininfo">' . user_login_string($course, $USER) . '</span>'; $time = time(); $hppassword = optional_param('hppassword', ''); if (HOTPOT_FIRST_ATTEMPT && !has_capability('mod/hotpot:grade', $context)) { // check this quiz is available to this student // error message, if quiz is unavailable $error = ''; // check quiz is visible if (!hotpot_is_visible($cm)) { $error = get_string("activityiscurrentlyhidden"); // check network address } else { if ($hotpot->subnet && !address_in_subnet(getremoteaddr(), $hotpot->subnet)) { $error = get_string("subneterror", "quiz"); // check number of attempts } else { if ($hotpot->attempts && $hotpot->attempts <= $DB->count_records_select('hotpot_attempts', 'hotpot=? AND userid=?', array($hotpot->id, $USER->id), 'COUNT(DISTINCT clickreportid)')) { $error = get_string("nomoreattempts", "quiz"); // get password } else { if ($hotpot->password && empty($hppassword)) { print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas, false); echo $OUTPUT->heading($hotpot->name); $boxalign = 'center'; $boxwidth = 500; if (trim(strip_tags($hotpot->summary))) { echo $OUTPUT->box_start("generalbox boxalign{$boxalign}"); print '<div class="mdl-align">' . format_text($hotpot->summary) . "</div>\n";
/* * Check time [open/close] */ $timenow = time(); if (!empty($reader->timeopen) && $reader->timeopen > $timenow) { error(get_string('quizopens', 'quiz') . ': ' . userdate($reader->timeopen)); } if (!empty($reader->timeclose) && $reader->timeclose < $timenow) { error(get_string('quizcloses', 'quiz') . ': ' . userdate($reader->timeclose)); } $alreadyansweredbooksid = array(); if (has_capability('mod/reader:manage', $contextmodule)) { require_once 'tabs.php'; } else { /// Check subnet access if ($reader->subnet && !address_in_subnet(getremoteaddr(), $reader->subnet)) { error(get_string("subneterror", "quiz"), "view.php?id=" . $id); } } $leveldata = reader_get_stlevel_data($reader); echo $OUTPUT->box_start('generalbox'); $table = new html_table(); if ($reader->pointreport == 1) { if ($reader->reportwordspoints != 1) { //1 - only points $table->head = array("Date", "Book Title", "Level", "Words", "Percent Correct", "Total Points"); $table->align = array("left", "left", "left", "center", "center", "center"); } else { $table->head = array("Date", "Book Title", "Level", "Percent Correct", "Total Points"); $table->align = array("left", "left", "left", "center", "center"); }
/** * Check netword restriction and return true o false * Network field may be a combination of ip, netmask and domain * comma separated to check. **/ function pass_network_check($netreq = null, $ip = null) { if ($netreq === null) { $netreq = $this->instance->requirednet; } $netreq = trim($netreq); if ($netreq == '') { // No net required return true; } if ($ip === null) { $ip = getremoteaddr(); } return address_in_subnet($ip, $netreq); }
admin_externalpage_print_header(); print_error('nosite', '', '', NULL, true); } $trusted_hosts = ''; //array(); $old_trusted_hosts = get_config('mnet', 'mnet_trusted_hosts'); if (!empty($old_trusted_hosts)) { $old_trusted_hosts = explode(',', $old_trusted_hosts); } else { $old_trusted_hosts = array(); } $test_ip_address = optional_param('testipaddress', NULL, PARAM_HOST); $in_range = false; if (!empty($test_ip_address)) { foreach ($old_trusted_hosts as $host) { if (address_in_subnet($test_ip_address, $host)) { $in_range = true; $validated_by = $host; break; } } } /// If data submitted, process and store if (($form = data_submitted()) && confirm_sesskey()) { $hostlist = preg_split("/[\\s,]+/", $form->hostlist); foreach ($hostlist as $host) { list($address, $mask) = explode('/', $host . '/'); if (empty($address)) { continue; } if (strlen($mask) == 0) {
/** * See if the request has the proper remote address * * @param Zend_Controller_Request_Http $request The request to check * @return boolean */ public function isValid($request) { if (!empty($this->_ipAddresses)) { $remoteaddr = getremoteaddr(); // Check for localhost IPv6 if (empty($remoteaddr) and $request->getServer('REMOTE_ADDR') == '::1') { $remoteaddr = '127.0.0.1'; } // Can get get the remote address ? if (empty($remoteaddr)) { $this->_setValue($request->getServer('REMOTE_ADDR')); $this->_error(self::NOT_FOUND); return false; } // Address valid ? if (!address_in_subnet($remoteaddr, $this->_ipAddresses)) { $this->_setValue($remoteaddr); $this->_error(self::NOT_VALID); return false; } } return true; }
/** * Will get called before the login page is shownr. Ff NTLM SSO * is enabled, and the user is in the right network, we'll redirect * to the magic NTLM page for SSO... * */ function loginpage_hook() { global $CFG, $SESSION; // HTTPS is potentially required //httpsrequired(); - this must be used before setting the URL, it is already done on the login/index.php if (($_SERVER['REQUEST_METHOD'] === 'GET' // Only on initial GET of loginpage || ($_SERVER['REQUEST_METHOD'] === 'POST' && (get_referer() != strip_querystring(qualified_me())))) // Or when POSTed from another place // See MDL-14071 && !empty($this->config->ntlmsso_enabled) // SSO enabled && !empty($this->config->ntlmsso_subnet) // have a subnet to test for && empty($_GET['authldap_skipntlmsso']) // haven't failed it yet && (isguestuser() || !isloggedin()) // guestuser or not-logged-in users && address_in_subnet(getremoteaddr(), $this->config->ntlmsso_subnet)) { // First, let's remember where we were trying to get to before we got here if (empty($SESSION->wantsurl)) { $SESSION->wantsurl = (array_key_exists('HTTP_REFERER', $_SERVER) && $_SERVER['HTTP_REFERER'] != $CFG->wwwroot && $_SERVER['HTTP_REFERER'] != $CFG->wwwroot.'/' && $_SERVER['HTTP_REFERER'] != $CFG->httpswwwroot.'/login/' && $_SERVER['HTTP_REFERER'] != $CFG->httpswwwroot.'/login/index.php') ? $_SERVER['HTTP_REFERER'] : NULL; } // Now start the whole NTLM machinery. if(!empty($this->config->ntlmsso_ie_fastpath)) { // Shortcut for IE browsers: skip the attempt page if(check_browser_version('MSIE')) { $sesskey = sesskey(); redirect($CFG->wwwroot.'/auth/ldap/ntlmsso_magic.php?sesskey='.$sesskey); } else { redirect($CFG->httpswwwroot.'/login/index.php?authldap_skipntlmsso=1'); } } else { redirect($CFG->wwwroot.'/auth/ldap/ntlmsso_attempt.php'); } } // No NTLM SSO, Use the normal login page instead. // If $SESSION->wantsurl is empty and we have a 'Referer:' header, the login // page insists on redirecting us to that page after user validation. If // we clicked on the redirect link at the ntlmsso_finish.php page (instead // of waiting for the redirection to happen) then we have a 'Referer:' header // we don't want to use at all. As we can't get rid of it, just point // $SESSION->wantsurl to $CFG->wwwroot (after all, we came from there). if (empty($SESSION->wantsurl) && (get_referer() == $CFG->httpswwwroot.'/auth/ldap/ntlmsso_finish.php')) { $SESSION->wantsurl = $CFG->wwwroot; } }
/** * Checks whether the input address is blocked by at any of the IPv4 or IPv6 address rules. * * @param string $addr the ip address to check. * @return bool true if the address is covered by an entry in the blacklist, false otherwise. */ protected function address_explicitly_blocked($addr) { $blockedhosts = $this->get_blacklisted_hosts_by_category(); $iphostsblocked = array_merge($blockedhosts['ipv4'], $blockedhosts['ipv6']); return address_in_subnet($addr, implode(',', $iphostsblocked)); }
/** * Require key login. Function terminates with error if key not found or incorrect. * @param string $script unique script identifier * @param int $instance optional instance id */ function require_user_key_login($script, $instance = null) { global $nomoodlecookie, $USER, $SESSION, $CFG; if (empty($nomoodlecookie)) { error('Incorrect use of require_key_login() - session cookies must be disabled!'); } /// extra safety @session_write_close(); $keyvalue = required_param('key', PARAM_ALPHANUM); if (!($key = get_record('user_private_key', 'script', $script, 'value', $keyvalue, 'instance', $instance))) { error('Incorrect key'); } if (!empty($key->validuntil) and $key->validuntil < time()) { error('Expired key'); } if ($key->iprestriction) { $remoteaddr = getremoteaddr(); if ($remoteaddr == '' or !address_in_subnet($remoteaddr, $key->iprestriction)) { error('Client IP address mismatch'); } } if (!($user = get_record('user', 'id', $key->userid))) { error('Incorrect user record'); } /// emulate normal session $SESSION = new object(); $USER = $user; /// note we are not using normal login if (!defined('USER_KEY_LOGIN')) { define('USER_KEY_LOGIN', true); } load_all_capabilities(); /// return isntance id - it might be empty return $key->instance; }
/** * Check if a server is located in a private network * @return true == private */ static function is_private_host($URL) { $host_name = parse_url($URL, PHP_URL_HOST); if ($host_name === false) { return true; } $private = '10., 127., 172.16.0.0/12, 192.168., 169.254.'; $name = $host_name . '.'; $IP = gethostbyname($name); if ($IP != $name) { return address_in_subnet($IP, $private); // IPv6 not implemented // fc00::/7 // fe80::/10 } return true; }
/** * Will get called before the login page is shownr. Ff NTLM SSO * is enabled, and the user is in the right network, we'll redirect * to the magic NTLM page for SSO... * */ function loginpage_hook() { global $CFG, $SESSION; // HTTPS is potentially required //httpsrequired(); - this must be used before setting the URL, it is already done on the login/index.php if (($_SERVER['REQUEST_METHOD'] === 'GET' || $_SERVER['REQUEST_METHOD'] === 'POST' && get_local_referer() != strip_querystring(qualified_me())) && !empty($this->config->ntlmsso_enabled) && !empty($this->config->ntlmsso_subnet) && empty($_GET['authldap_skipntlmsso']) && (isguestuser() || !isloggedin()) && address_in_subnet(getremoteaddr(), $this->config->ntlmsso_subnet)) { // First, let's remember where we were trying to get to before we got here if (empty($SESSION->wantsurl)) { $SESSION->wantsurl = null; $referer = get_local_referer(false); if ($referer && $referer != $CFG->wwwroot && $referer != $CFG->wwwroot . '/' && $referer != $CFG->httpswwwroot . '/login/' && $referer != $CFG->httpswwwroot . '/login/index.php') { $SESSION->wantsurl = $referer; } } // Now start the whole NTLM machinery. if ($this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESATTEMPT || $this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESFORM) { if (core_useragent::is_ie()) { $sesskey = sesskey(); redirect($CFG->wwwroot . '/auth/ldap/ntlmsso_magic.php?sesskey=' . $sesskey); } else { if ($this->config->ntlmsso_ie_fastpath == AUTH_NTLM_FASTPATH_YESFORM) { redirect($CFG->httpswwwroot . '/login/index.php?authldap_skipntlmsso=1'); } } } redirect($CFG->wwwroot . '/auth/ldap/ntlmsso_attempt.php'); } // No NTLM SSO, Use the normal login page instead. // If $SESSION->wantsurl is empty and we have a 'Referer:' header, the login // page insists on redirecting us to that page after user validation. If // we clicked on the redirect link at the ntlmsso_finish.php page (instead // of waiting for the redirection to happen) then we have a 'Referer:' header // we don't want to use at all. As we can't get rid of it, just point // $SESSION->wantsurl to $CFG->wwwroot (after all, we came from there). if (empty($SESSION->wantsurl) && get_local_referer() == $CFG->httpswwwroot . '/auth/ldap/ntlmsso_finish.php') { $SESSION->wantsurl = $CFG->wwwroot; } }
} $button = update_module_button($cm->id, $course->id, get_string("modulename", "hotpot")); $button = '<div style="font-size:0.75em;">' . $button . '</div>'; $loggedinas = '<span class="logininfo">' . user_login_string($course, $USER) . '</span>'; $time = time(); $hppassword = optional_param('hppassword', ''); if (HOTPOT_FIRST_ATTEMPT && !has_capability('mod/hotpot:grade', $context)) { // check this quiz is available to this student // error message, if quiz is unavailable $error = ''; // check quiz is visible if (!hotpot_is_visible($cm)) { $error = get_string("activityiscurrentlyhidden"); // check network address } else { if ($hotpot->subnet && !address_in_subnet($_SERVER['REMOTE_ADDR'], $hotpot->subnet)) { $error = get_string("subneterror", "quiz"); // check number of attempts } else { if ($hotpot->attempts && $hotpot->attempts <= count_records_select('hotpot_attempts', 'hotpot=' . $hotpot->id . ' AND userid=' . $USER->id, 'COUNT(DISTINCT clickreportid)')) { $error = get_string("nomoreattempts", "quiz"); // get password } else { if ($hotpot->password && empty($hppassword)) { print_header($title, $heading, $navigation, "", "", true, $button, $loggedinas, false); print_heading($hotpot->name); $boxalign = 'center'; $boxwidth = 500; if (trim(strip_tags($hotpot->summary))) { print_simple_box_start($boxalign, $boxwidth); print '<div align="center">' . format_text($hotpot->summary) . "</div>\n";
$buttonoptions['forcenew'] = true; echo '<div class="controls">'; print_single_button($CFG->wwwroot . '/mod/quiz/attempt.php', $buttonoptions, get_string('startagain', 'quiz')); echo '</div>'; /// Notices about restrictions that would affect students. if ($quiz->popup == 1) { notify(get_string('popupnotice', 'quiz')); } else { if ($quiz->popup == 2) { notify(get_string('safebrowsernotice', 'quiz')); } } if ($timestamp < $quiz->timeopen || $quiz->timeclose && $timestamp > $quiz->timeclose) { notify(get_string('notavailabletostudents', 'quiz')); } if ($quiz->subnet && !address_in_subnet(getremoteaddr(), $quiz->subnet)) { notify(get_string('subnetnotice', 'quiz')); } } else { if ($quiz->attempts != 1) { print_heading(format_string($quiz->name) . ' - ' . $strattemptnum); } else { print_heading(format_string($quiz->name)); } } // Start the form $quiz->thispageurl = $CFG->wwwroot . '/mod/quiz/attempt.php?q=' . s($quiz->id) . '&page=' . s($page); $quiz->cmid = $cm->id; echo '<form id="responseform" method="post" action="', $quiz->thispageurl . '" enctype="multipart/form-data"' . ' onkeypress="return check_enter(event);" accept-charset="utf-8">', "\n"; echo '<script type="text/javascript">', "\n", 'document.getElementById("responseform").setAttribute("autocomplete", "off")', "\n", "</script>\n"; if ($quiz->timelimit > 0) {
/** * Is current ip in give list? * * @param string $list * @return bool */ function remoteip_in_list($list) { $inlist = false; $client_ip = getremoteaddr(); $list = explode("\n", $list); foreach ($list as $subnet) { $subnet = trim($subnet); if (address_in_subnet($client_ip, $subnet)) { $inlist = true; break; } } return $inlist; }
public function test_address_in_subnet() { // 1: xxx.xxx.xxx.xxx/nn or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/nnn (number of bits in net mask). $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.1/32')); $this->assertFalse(address_in_subnet('123.121.23.1', '123.121.23.0/32')); $this->assertTrue(address_in_subnet('10.10.10.100', '123.121.23.45/0')); $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.0/24')); $this->assertFalse(address_in_subnet('123.121.34.1', '123.121.234.0/24')); $this->assertTrue(address_in_subnet('123.121.234.1', '123.121.234.0/30')); $this->assertFalse(address_in_subnet('123.121.23.8', '123.121.23.0/30')); $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba/128')); $this->assertFalse(address_in_subnet('bab:baba::baba', 'bab:baba::cece/128')); $this->assertTrue(address_in_subnet('baba:baba::baba', 'cece:cece::cece/0')); $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba/128')); $this->assertTrue(address_in_subnet('baba:baba::00ba', 'baba:baba::/120')); $this->assertFalse(address_in_subnet('baba:baba::aba', 'baba:baba::/120')); $this->assertTrue(address_in_subnet('baba::baba:00ba', 'baba::baba:0/112')); $this->assertFalse(address_in_subnet('baba::aba:00ba', 'baba::baba:0/112')); $this->assertFalse(address_in_subnet('aba::baba:0000', 'baba::baba:0/112')); // Fixed input. $this->assertTrue(address_in_subnet('123.121.23.1 ', ' 123.121.23.0 / 24')); $this->assertTrue(address_in_subnet('::ffff:10.1.1.1', ' 0:0:0:000:0:ffff:a1:10 / 126')); // Incorrect input. $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/-2')); $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/64')); $this->assertFalse(address_in_subnet('123.121.234.x', '123.121.234.1/24')); $this->assertFalse(address_in_subnet('123.121.234.0', '123.121.234.xx/24')); $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.1/xx0')); $this->assertFalse(address_in_subnet('::1', '::aa:0/xx0')); $this->assertFalse(address_in_subnet('::1', '::aa:0/-5')); $this->assertFalse(address_in_subnet('::1', '::aa:0/130')); $this->assertFalse(address_in_subnet('x:1', '::aa:0/130')); $this->assertFalse(address_in_subnet('::1', '::ax:0/130')); // 2: xxx.xxx.xxx.xxx-yyy or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::xxxx-yyyy (a range of IP addresses in the last group). $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12-14')); $this->assertTrue(address_in_subnet('123.121.234.13', '123.121.234.12-14')); $this->assertTrue(address_in_subnet('123.121.234.14', '123.121.234.12-14')); $this->assertFalse(address_in_subnet('123.121.234.1', '123.121.234.12-14')); $this->assertFalse(address_in_subnet('123.121.234.20', '123.121.234.12-14')); $this->assertFalse(address_in_subnet('123.121.23.12', '123.121.234.12-14')); $this->assertFalse(address_in_subnet('123.12.234.12', '123.121.234.12-14')); $this->assertTrue(address_in_subnet('baba:baba::baba', 'baba:baba::baba-babe')); $this->assertTrue(address_in_subnet('baba:baba::babc', 'baba:baba::baba-babe')); $this->assertTrue(address_in_subnet('baba:baba::babe', 'baba:baba::baba-babe')); $this->assertFalse(address_in_subnet('bab:baba::bab0', 'bab:baba::baba-babe')); $this->assertFalse(address_in_subnet('bab:baba::babf', 'bab:baba::baba-babe')); $this->assertFalse(address_in_subnet('bab:baba::bfbe', 'bab:baba::baba-babe')); $this->assertFalse(address_in_subnet('bfb:baba::babe', 'bab:baba::baba-babe')); // Fixed input. $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12 - 14 ')); $this->assertTrue(address_in_subnet('bab:baba::babe', 'bab:baba::baba - babe ')); // Incorrect input. $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12-234.14')); $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12-256')); $this->assertFalse(address_in_subnet('123.121.234.12', '123.121.234.12--256')); // 3: xxx.xxx or xxx.xxx. or xxx:xxx:xxxx or xxx:xxx:xxxx. (incomplete address, a bit non-technical ;-). $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.12')); $this->assertFalse(address_in_subnet('123.121.23.12', '123.121.23.13')); $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234.')); $this->assertTrue(address_in_subnet('123.121.234.12', '123.121.234')); $this->assertTrue(address_in_subnet('123.121.234.12', '123.121')); $this->assertTrue(address_in_subnet('123.121.234.12', '123')); $this->assertFalse(address_in_subnet('123.121.234.1', '12.121.234.')); $this->assertFalse(address_in_subnet('123.121.234.1', '12.121.234')); $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:baba::bab')); $this->assertFalse(address_in_subnet('baba:baba::ba', 'baba:baba::bc')); $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:baba')); $this->assertTrue(address_in_subnet('baba:baba::bab', 'baba:')); $this->assertFalse(address_in_subnet('bab:baba::bab', 'baba:')); // Multiple subnets. $this->assertTrue(address_in_subnet('123.121.234.12', '::1/64, 124., 123.121.234.10-30')); $this->assertTrue(address_in_subnet('124.121.234.12', '::1/64, 124., 123.121.234.10-30')); $this->assertTrue(address_in_subnet('::2', '::1/64, 124., 123.121.234.10-30')); $this->assertFalse(address_in_subnet('12.121.234.12', '::1/64, 124., 123.121.234.10-30')); // Other incorrect input. $this->assertFalse(address_in_subnet('123.123.123.123', '')); }
/** * Function to check the passed address is within the passed subnet * * The parameter is a comma separated string of subnet definitions. * Subnet strings can be in one of three formats: * 1: xxx.xxx.xxx.xxx/nn or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/nnn (number of bits in net mask) * 2: xxx.xxx.xxx.xxx-yyy or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::xxxx-yyyy (a range of IP addresses in the last group) * 3: xxx.xxx or xxx.xxx. or xxx:xxx:xxxx or xxx:xxx:xxxx. (incomplete address, a bit non-technical ;-) * Code for type 1 modified from user posted comments by mediator at * {@link http://au.php.net/manual/en/function.ip2long.php} * * @param string $addr The address you are checking * @param string $subnetstr The string of subnet addresses * @return bool */ function address_in_subnet($addr, $subnetstr) { if ($addr == '0.0.0.0') { return false; } $subnets = explode(',', $subnetstr); $found = false; $addr = trim($addr); // normalise $addr = cleanremoteaddr($addr, false); if ($addr === null) { return false; } $addrparts = explode(':', $addr); $ipv6 = strpos($addr, ':'); foreach ($subnets as $subnet) { $subnet = trim($subnet); if ($subnet === '') { continue; } if (strpos($subnet, '/') !== false) { ///1: xxx.xxx.xxx.xxx/nn or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx/nnn list($ip, $mask) = explode('/', $subnet); $mask = trim($mask); if (!is_number($mask)) { // incorect mask number, eh? continue; } // normalise $ip = cleanremoteaddr($ip, false); if ($ip === null) { continue; } if (strpos($ip, ':') !== false) { // IPv6 if (!$ipv6) { continue; } if ($mask > 128 or $mask < 0) { // nonsense continue; } if ($mask == 0) { // any address return true; } if ($mask == 128) { if ($ip === $addr) { return true; } continue; } $ipparts = explode(':', $ip); $modulo = $mask % 16; $ipnet = array_slice($ipparts, 0, ($mask - $modulo) / 16); $addrnet = array_slice($addrparts, 0, ($mask - $modulo) / 16); if (implode(':', $ipnet) === implode(':', $addrnet)) { if ($modulo == 0) { return true; } $pos = ($mask - $modulo) / 16; $ipnet = hexdec($ipparts[$pos]); $addrnet = hexdec($addrparts[$pos]); $mask = 0xffff << 16 - $modulo; if (($addrnet & $mask) == ($ipnet & $mask)) { return true; } } } else { // IPv4 if ($ipv6) { continue; } if ($mask > 32 or $mask < 0) { // nonsense continue; } if ($mask == 0) { return true; } if ($mask == 32) { if ($ip === $addr) { return true; } continue; } $mask = 4294967295.0 << 32 - $mask; if ((ip2long($addr) & $mask) == (ip2long($ip) & $mask)) { return true; } } } else { if (strpos($subnet, '-') !== false) { /// 2: xxx.xxx.xxx.xxx-yyy or xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx::xxxx-yyyy ...a range of IP addresses in the last group. $parts = explode('-', $subnet); if (count($parts) != 2) { continue; } if (strpos($subnet, ':') !== false) { // IPv6 if (!$ipv6) { continue; } // normalise $ipstart = cleanremoteaddr(trim($parts[0]), false); if ($ipstart === null) { continue; } $ipparts = explode(':', $ipstart); $start = hexdec(array_pop($ipparts)); $ipparts[] = trim($parts[1]); // normalise $ipend = cleanremoteaddr(implode(':', $ipparts), false); if ($ipend === null) { continue; } $ipparts[7] = ''; $ipnet = implode(':', $ipparts); if (strpos($addr, $ipnet) !== 0) { continue; } $ipparts = explode(':', $ipend); $end = hexdec($ipparts[7]); $addrend = hexdec($addrparts[7]); if ($addrend >= $start and $addrend <= $end) { return true; } } else { // IPv4 if ($ipv6) { continue; } // normalise $ipstart = cleanremoteaddr(trim($parts[0]), false); if ($ipstart === null) { continue; } $ipparts = explode('.', $ipstart); $ipparts[3] = trim($parts[1]); // normalise $ipend = cleanremoteaddr(implode('.', $ipparts), false); if ($ipend === null) { continue; } if (ip2long($addr) >= ip2long($ipstart) and ip2long($addr) <= ip2long($ipend)) { return true; } } } else { /// 3: xxx.xxx or xxx.xxx. or xxx:xxx:xxxx or xxx:xxx:xxxx. if (strpos($subnet, ':') !== false) { // IPv6 if (!$ipv6) { continue; } $parts = explode(':', $subnet); $count = count($parts); if ($parts[$count - 1] === '') { // trim trailing : unset($parts[$count - 1]); $count--; $subnet = implode('.', $parts); } // normalise $isip = cleanremoteaddr($subnet, false); if ($isip !== null) { if ($isip === $addr) { return true; } continue; } else { if ($count > 8) { continue; } } $zeros = array_fill(0, 8 - $count, '0'); $subnet = $subnet . ':' . implode(':', $zeros) . '/' . $count * 16; if (address_in_subnet($addr, $subnet)) { return true; } } else { // IPv4 if ($ipv6) { continue; } $parts = explode('.', $subnet); $count = count($parts); if ($parts[$count - 1] === '') { // trim trailing . unset($parts[$count - 1]); $count--; $subnet = implode('.', $parts); } if ($count == 4) { // normalise $subnet = cleanremoteaddr($subnet, false); if ($subnet === $addr) { return true; } continue; } else { if ($count > 4) { continue; } } $zeros = array_fill(0, 4 - $count, '0'); $subnet = $subnet . '.' . implode('.', $zeros) . '/' . $count * 8; if (address_in_subnet($addr, $subnet)) { return true; } } } } } return false; }