From 08aa23227e45053117d273e517d7f386edc117ff Mon Sep 17 00:00:00 2001 From: Dries Buytaert Date: Tue, 8 Apr 2008 22:50:55 +0000 Subject: [PATCH] - Patch #228594 by catch et al: removed access rule functionality from core. The access rules capability of user module has been stripped down to a simple method for blocking IP addresses. E-mail and username restrictions are now available in a contributed module. IP address range blocking is no longer supported and should be done at the server level. This patch is partly motiviated by the fact that at the usability testing, it frequently came up that users went to "access rules" when trying to configure their site settings. --- CHANGELOG.txt | 5 + includes/bootstrap.inc | 43 +++---- modules/system/system.admin.inc | 88 +++++++++++++ modules/system/system.install | 87 +++++++++++++ modules/system/system.module | 50 ++++++++ modules/user/user-rtl.css | 5 - modules/user/user.admin.inc | 200 ----------------------------- modules/user/user.css | 10 -- modules/user/user.install | 33 ----- modules/user/user.module | 74 +---------- sites/default/default.settings.php | 23 ++++ 11 files changed, 278 insertions(+), 340 deletions(-) diff --git a/CHANGELOG.txt b/CHANGELOG.txt index 194c08682f0..542e04b1d03 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -15,6 +15,11 @@ Drupal 7.0, xxxx-xx-xx (development version) - Removed ping module: * This module has been removed from the core download. Contributed alternatives are available. +- Removed access rules: + * The access rules capability of user module has been stripped down to a + simple method for blocking IP addresses. E-mail and username restrictions + are now available in a contributed module. IP address range blocking is + no longer supported and should be done at the server level. Drupal 6.0, 2008-02-13 ---------------------- diff --git a/includes/bootstrap.inc b/includes/bootstrap.inc index 3bc24f1e6fe..106320c250a 100644 --- a/includes/bootstrap.inc +++ b/includes/bootstrap.inc @@ -847,31 +847,30 @@ function drupal_get_messages($type = NULL, $clear_queue = TRUE) { } /** - * Perform an access check for a given mask and rule type. Rules are usually - * created via admin/user/rules page. + * Check to see if an IP address has been blocked. * - * If any allow rule matches, access is allowed. Otherwise, if any deny rule - * matches, access is denied. If no rule matches, access is allowed. + * Blocked IP addresses are stored in the database by default. However for + * performance reasons we allow an override in settings.php. This allows us + * to avoid querying the database at this critical stage of the bootstrap if + * an administrative interface for IP address blocking is not required. * - * @param $type string - * Type of access to check: Allowed values are: - * - 'host': host name or IP address - * - 'mail': e-mail address - * - 'user': username - * @param $mask string - * String or mask to test: '_' matches any character, '%' matches any - * number of characters. + * @param $ip string + * IP address to check. * @return bool * TRUE if access is denied, FALSE if access is allowed. */ -function drupal_is_denied($type, $mask) { - // Because this function is called for every page request, both cached - // and non-cached pages, we tried to optimize it as much as possible. - // We deny access if the only matching records in the {access} table have - // status 0 (deny). If any have status 1 (allow), or if there are no - // matching records, we allow access. - $sql = "SELECT 1 FROM {access} WHERE type = '%s' AND LOWER('%s') LIKE LOWER(mask) AND status = %d"; - return db_result(db_query_range($sql, $type, $mask, 0, 0, 1)) && !db_result(db_query_range($sql, $type, $mask, 1, 0, 1)); +function drupal_is_denied($ip) { + // Because this function is called on every page request, we first check + // for an array of IP addresses in settings.php before querying the + // database. + $blocked_ips = variable_get('blocked_ips', NULL); + if (isset($blocked_ips) && is_array($blocked_ips)) { + return in_array($ip, $blocked_ips); + } + else { + $sql = "SELECT 1 FROM {blocked_ips} WHERE ip = '%s'"; + return (bool) db_result(db_query($sql, $ip)); + } } /** @@ -953,8 +952,8 @@ function _drupal_bootstrap($phase) { break; case DRUPAL_BOOTSTRAP_ACCESS: - // Deny access to hosts which were banned - t() is not yet available. - if (drupal_is_denied('host', ip_address())) { + // Deny access to blocked IP addresses - t() is not yet available. + if (drupal_is_denied(ip_address())) { header('HTTP/1.1 403 Forbidden'); print 'Sorry, '. check_plain(ip_address()) .' has been banned.'; exit(); diff --git a/modules/system/system.admin.inc b/modules/system/system.admin.inc index 76c52c65676..318c7f6fa07 100644 --- a/modules/system/system.admin.inc +++ b/modules/system/system.admin.inc @@ -1105,6 +1105,94 @@ function system_modules_uninstall_submit($form, &$form_state) { } } +/** + * Menu callback. Display blocked IP addresses. + */ +function system_ip_blocking() { + $output = ''; + $rows = array(); + $header = array(t('IP address'), t('Operations')); + $result = db_query('SELECT * FROM {blocked_ips}'); + while ($ip = db_fetch_object($result)) { + $rows[] = array( + $ip->ip, + l(t('delete'), "admin/settings/ip-blocking/delete/$ip->iid"), + ); + } + + $output .= theme('table', $header, $rows); + + $output .= drupal_get_form('system_ip_blocking_form'); + + return $output; +} + +/** + * Define the form for blocking IP addresses. + * + * @ingroup forms + * @see system_ip_blocking_form_validate() + * @see system_ip_blocking_form_submit() + */ +function system_ip_blocking_form($form_state) { + $form['ip'] = array( + '#title' => t('IP address'), + '#type' => 'textfield', + '#size' => 64, + '#maxlength' => 32, + '#description' => t('Enter a valid IP address.'), + ); + $form['submit'] = array( + '#type' => 'submit', + '#value' => t('Save'), + ); + $form['#submit'][] = 'system_ip_blocking_form_submit'; + $form['#validate'][] = 'system_ip_blocking_form_validate'; + return $form; +} + +function system_ip_blocking_form_validate($form, &$form_state) { + $ip = $form_state['values']['ip']; + if (db_result(db_query("SELECT * FROM {blocked_ips} WHERE ip = '%s'", $ip))) { + form_set_error('ip', t('This IP address is already blocked.')); + } + else if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE) == FALSE) { + form_set_error('ip', t('Please enter a valid IP address.')); + } +} + +function system_ip_blocking_form_submit($form, &$form_state) { + $ip = $form_state['values']['ip']; + db_query("INSERT INTO {blocked_ips} (ip) VALUES ('%s')", $ip); + drupal_set_message(t('The IP address %ip has been blocked.', array('%ip' => $ip))); + $form_state['redirect'] = 'admin/settings/ip-blocking'; + return; +} + +/** + * IP deletion confirm page. + * + * @see system_ip_blocking_delete_submit() + */ +function system_ip_blocking_delete(&$form_state, $iid) { + $form['blocked_ip'] = array( + '#type' => 'value', + '#value' => $iid, + ); + return confirm_form($form, t('Are you sure you want to delete %ip?', array('%ip' => $iid['ip'])), 'admin/settings/ip-blocking', t('This action cannot be undone.'), t('Delete'), t('Cancel')); +} + +/** + * Process system_ip_blocking_delete form submissions. + */ +function system_ip_blocking_delete_submit($form, &$form_state) { + $blocked_ip = $form_state['values']['blocked_ip']; + db_query("DELETE FROM {blocked_ips} WHERE iid = %d", $blocked_ip['iid']); + watchdog('user', 'Deleted %ip', array('%ip' => $blocked_ip['ip'])); + drupal_set_message(t('The IP address %ip was deleted.', array('%ip' => $blocked_ip['ip']))); + $form_state['redirect'] = 'admin/settings/ip-blocking'; +} + /** * Form builder; The general site information form. * diff --git a/modules/system/system.install b/modules/system/system.install index fc78a4db218..6d627c8bdfc 100644 --- a/modules/system/system.install +++ b/modules/system/system.install @@ -527,6 +527,29 @@ function system_schema() { ), ); + $schema['blocked_ips'] = array( + 'description' => t('Stores blocked IP addresses.'), + 'fields' => array( + 'iid' => array( + 'description' => t('Primary Key: unique ID for IP addresses.'), + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'ip' => array( + 'description' => t('IP address'), + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + ), + ), + 'indexes' => array( + 'blocked_ip' => array('ip'), + ), + 'primary key' => array('iid'), + ); + $schema['cache'] = array( 'description' => t('Generic cache table for caching things not separated out into their own tables. Contributed modules may also use this to store cached items.'), 'fields' => array( @@ -2668,6 +2691,70 @@ function system_update_7001() { return $ret; } +/** + * Add a table to store blocked IP addresses. + */ +function system_update_7002() { + $ret = array(); + $schema['blocked_ips'] = array( + 'description' => t('Stores blocked IP addresses.'), + 'fields' => array( + 'iid' => array( + 'description' => t('Primary Key: unique ID for IP addresses.'), + 'type' => 'serial', + 'unsigned' => TRUE, + 'not null' => TRUE, + ), + 'ip' => array( + 'description' => t('IP address'), + 'type' => 'varchar', + 'length' => 32, + 'not null' => TRUE, + 'default' => '', + ), + ), + 'indexes' => array( + 'blocked_ip' => array('ip'), + ), + 'primary key' => array('iid'), + ); + + db_create_table($ret, 'blocked_ips', $schema['blocked_ips']); + + return $ret; +} + +/** + * Update {blocked_ips} with valid IP addresses from {access}. + */ +function system_update_7003() { + $ret = array(); + $type = 'host'; + $result = db_query("SELECT mask FROM {access} WHERE status = %d AND TYPE = '%s'", 0, $type); + while ($blocked = db_fetch_object($result)) { + if (filter_var($blocked->mask, FILTER_VALIDATE_IP, FILTER_FLAG_NO_RES_RANGE) !== FALSE) { + $ret[] = update_sql("INSERT INTO {blocked_ips} (ip) VALUES ('$blocked->mask')"); + } + else { + $invalid_host = check_plain($blocked->mask); + $ret[] = array('success' => TRUE, 'query' => 'The host '. $invalid_host .' is no longer blocked because it is not a valid IP address.'); + } + } + if (isset($invalid_host)) { + drupal_set_message('Drupal no longer supports wildcard IP address blocking. Visitors whose IP addresses match ranges you have previously set using access rules will no longer be blocked from your site when you take it out of maintenance mode. See the IP address and referrer blocking Handbook page for alternative methods.', 'warning'); + $ret[] = array('success' => TRUE, 'query' => ''); + } + // Make sure not to block any IP addresses that were specifically allowed by access rules. + if (!empty($result)) { + $result = db_query("SELECT mask FROM {access} WHERE status = %d AND type = '%s'", 1, $type); + while ($allowed = db_fetch_object($result)) { + $ret[] = update_sql("DELETE FROM {blocked_ips} WHERE LOWER(ip) LIKE LOWER('$allowed->mask')"); + } + } + + return $ret; +} + /** * @} End of "defgroup updates-6.x-to-7.x" diff --git a/modules/system/system.module b/modules/system/system.module index 82d74a44949..bc41ce0182c 100644 --- a/modules/system/system.module +++ b/modules/system/system.module @@ -99,6 +99,8 @@ function system_help($path, $arg) { return $output; case 'admin/settings/actions/configure': return t('An advanced action offers additional configuration options which may be filled out below. Changing the Description field is recommended, in order to better identify the precise action taking place. This description will be displayed in modules such as the trigger module when assigning actions to system events, so it is best if it is as descriptive as possible (for example, "Send e-mail to Moderation Team" rather than simply "Send e-mail").'); + case 'admin/settings/ip-blocking': + return '

'. t('IP addresses listed here are blocked from your site before any modules are loaded. You may add IP addresses to the list, or delete existing entries.') .'

'; case 'admin/reports/status': return '

'. t("Here you can find a short overview of your site's parameters as well as any problems detected with your installation. It may be useful to copy and paste this information into support requests filed on drupal.org's support forums and project issue queues.") .'

'; } @@ -163,6 +165,7 @@ function system_perm() { 'access site reports' => t('View reports from system logs and other status information.'), 'select different theme' => t('Select a theme other than the default theme set by the site administrator.'), 'administer files' => t('Manage user-uploaded files.'), + 'block IP addresses' => t('Block IP addresses from accessing your site.'), ); } @@ -486,6 +489,23 @@ function system_menu() { 'type' => MENU_CALLBACK, ); + // IP address blocking. + $items['admin/settings/ip-blocking'] = array( + 'title' => 'IP address blocking', + 'description' => 'Manage blocked IP addresses.', + 'page callback' => 'system_ip_blocking', + 'access arguments' => array('block IP addresses'), + 'file' => 'system.admin.inc', + ); + $items['admin/settings/ip-blocking/delete/%blocked_ip'] = array( + 'title' => 'Delete IP address', + 'page callback' => 'drupal_get_form', + 'page arguments' => array('system_ip_blocking_delete', 4), + 'access arguments' => array('block IP addresses'), + 'type' => MENU_CALLBACK, + 'file' => 'system.admin.inc', + ); + // Settings: $items['admin/settings/site-information'] = array( 'title' => 'Site information', @@ -635,6 +655,20 @@ function system_menu() { return $items; } +/** + * Retrieve a blocked IP address from the database. + * + * @param $iid integer + * The ID of the blocked IP address to retrieve. + * + * @return + * The blocked IP address from the database as an array. + */ +function blocked_ip_load($iid) { + $blocked_ip = db_fetch_array(db_query("SELECT * FROM {blocked_ips} WHERE iid = %d", $iid)); + return $blocked_ip; +} + /** * Menu item access callback - only admin or enabled themes can be accessed. */ @@ -1408,6 +1442,12 @@ function system_action_info() { 'taxonomy' => array('insert', 'update', 'delete'), ) ), + 'system_block_ip_action' => array( + 'description' => t('Ban IP address of current user'), + 'type' => 'user', + 'configurable' => FALSE, + 'hooks' => array(), + ), 'system_goto_action' => array( 'description' => t('Redirect to URL'), 'type' => 'system', @@ -1963,6 +2003,16 @@ function system_goto_action($object, $context) { drupal_goto($context['url']); } +/** + * Implementation of a Drupal action. + * Blocks the user's IP address. + */ +function system_block_ip_action() { + $ip = ip_address(); + db_query("INSERT INTO {blocked_ips} (ip) VALUES ('%s')", $ip);; + watchdog('action', 'Banned IP address %ip', array('%ip' => $ip)); +} + /** * Generate an array of time zones and their local time&date. */ diff --git a/modules/user/user-rtl.css b/modules/user/user-rtl.css index ea0278ba32d..219b0cf7c4c 100644 --- a/modules/user/user-rtl.css +++ b/modules/user/user-rtl.css @@ -4,11 +4,6 @@ padding-left: 0; padding-right: 1.5em; } -#access-rules .access-type, #access-rules .rule-type { - margin-right: 0; - margin-left: 1em; - float: right; -} #user-admin-buttons { float: right; margin-left: 0; diff --git a/modules/user/user.admin.inc b/modules/user/user.admin.inc index 3e554151e31..8174878a490 100644 --- a/modules/user/user.admin.inc +++ b/modules/user/user.admin.inc @@ -711,206 +711,6 @@ function user_admin_role_submit($form, &$form_state) { return; } -/** - * Menu callback: list all access rules - */ -function user_admin_access_check() { - $output = drupal_get_form('user_admin_check_user'); - $output .= drupal_get_form('user_admin_check_mail'); - $output .= drupal_get_form('user_admin_check_host'); - return $output; -} - -/** - * Menu callback: add an access rule - */ -function user_admin_access_add($mask = NULL, $type = NULL) { - if ($edit = $_POST) { - if (!$edit['mask']) { - form_set_error('mask', t('You must enter a mask.')); - } - else { - db_query("INSERT INTO {access} (mask, type, status) VALUES ('%s', '%s', %d)", $edit['mask'], $edit['type'], $edit['status']); - $aid = db_last_insert_id('access', 'aid'); - drupal_set_message(t('The access rule has been added.')); - drupal_goto('admin/user/rules'); - } - } - else { - $edit['mask'] = $mask; - $edit['type'] = $type; - } - return drupal_get_form('user_admin_access_add_form', $edit, t('Add rule')); -} - -/** - * Menu callback: edit an access rule - */ -function user_admin_access_edit($aid = 0) { - if ($edit = $_POST) { - if (!$edit['mask']) { - form_set_error('mask', t('You must enter a mask.')); - } - else { - db_query("UPDATE {access} SET mask = '%s', type = '%s', status = '%s' WHERE aid = %d", $edit['mask'], $edit['type'], $edit['status'], $aid); - drupal_set_message(t('The access rule has been saved.')); - drupal_goto('admin/user/rules'); - } - } - else { - $edit = db_fetch_array(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid)); - } - return drupal_get_form('user_admin_access_edit_form', $edit, t('Save rule')); -} - -/** - * Form builder; Configure access rules. - * - * @ingroup forms - */ -function user_admin_access_form(&$form_state, $edit, $submit) { - $form['status'] = array( - '#type' => 'radios', - '#title' => t('Access type'), - '#default_value' => isset($edit['status']) ? $edit['status'] : 0, - '#options' => array('1' => t('Allow'), '0' => t('Deny')), - ); - $type_options = array('user' => t('Username'), 'mail' => t('E-mail'), 'host' => t('Host')); - $form['type'] = array( - '#type' => 'radios', - '#title' => t('Rule type'), - '#default_value' => (isset($type_options[$edit['type']]) ? $edit['type'] : 'user'), - '#options' => $type_options, - ); - $form['mask'] = array( - '#type' => 'textfield', - '#title' => t('Mask'), - '#size' => 30, - '#maxlength' => 64, - '#default_value' => $edit['mask'], - '#description' => '%: '. t('Matches any number of characters, even zero characters') .'.
_: '. t('Matches exactly one character.'), - '#required' => TRUE, - ); - $form['submit'] = array('#type' => 'submit', '#value' => $submit); - - return $form; -} - -function user_admin_access_check_validate($form, &$form_state) { - if (empty($form_state['values']['test'])) { - form_set_error($form_state['values']['type'], t('No value entered. Please enter a test string and try again.')); - } -} - -function user_admin_check_user() { - $form['user'] = array('#type' => 'fieldset', '#title' => t('Username')); - $form['user']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter a username to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => USERNAME_MAX_LENGTH); - $form['user']['type'] = array('#type' => 'hidden', '#value' => 'user'); - $form['user']['submit'] = array('#type' => 'submit', '#value' => t('Check username')); - $form['#submit'][] = 'user_admin_access_check_submit'; - $form['#validate'][] = 'user_admin_access_check_validate'; - $form['#theme'] = 'user_admin_access_check'; - return $form; -} - -function user_admin_check_mail() { - $form['mail'] = array('#type' => 'fieldset', '#title' => t('E-mail')); - $form['mail']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter an e-mail address to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => EMAIL_MAX_LENGTH); - $form['mail']['type'] = array('#type' => 'hidden', '#value' => 'mail'); - $form['mail']['submit'] = array('#type' => 'submit', '#value' => t('Check e-mail')); - $form['#submit'][] = 'user_admin_access_check_submit'; - $form['#validate'][] = 'user_admin_access_check_validate'; - $form['#theme'] = 'user_admin_access_check'; - return $form; -} - -function user_admin_check_host() { - $form['host'] = array('#type' => 'fieldset', '#title' => t('Hostname')); - $form['host']['test'] = array('#type' => 'textfield', '#title' => '', '#description' => t('Enter a hostname or IP address to check if it will be denied or allowed.'), '#size' => 30, '#maxlength' => 64); - $form['host']['type'] = array('#type' => 'hidden', '#value' => 'host'); - $form['host']['submit'] = array('#type' => 'submit', '#value' => t('Check hostname')); - $form['#submit'][] = 'user_admin_access_check_submit'; - $form['#validate'][] = 'user_admin_access_check_validate'; - $form['#theme'] = 'user_admin_access_check'; - return $form; -} - -function user_admin_access_check_submit($form, &$form_state) { - switch ($form_state['values']['type']) { - case 'user': - if (drupal_is_denied('user', $form_state['values']['test'])) { - drupal_set_message(t('The username %name is not allowed.', array('%name' => $form_state['values']['test']))); - } - else { - drupal_set_message(t('The username %name is allowed.', array('%name' => $form_state['values']['test']))); - } - break; - case 'mail': - if (drupal_is_denied('mail', $form_state['values']['test'])) { - drupal_set_message(t('The e-mail address %mail is not allowed.', array('%mail' => $form_state['values']['test']))); - } - else { - drupal_set_message(t('The e-mail address %mail is allowed.', array('%mail' => $form_state['values']['test']))); - } - break; - case 'host': - if (drupal_is_denied('host', $form_state['values']['test'])) { - drupal_set_message(t('The hostname %host is not allowed.', array('%host' => $form_state['values']['test']))); - } - else { - drupal_set_message(t('The hostname %host is allowed.', array('%host' => $form_state['values']['test']))); - } - break; - default: - break; - } -} - -/** - * Menu callback: delete an access rule - * - * @ingroup forms - * @see user_admin_access_delete_confirm_submit() - */ -function user_admin_access_delete_confirm($form_state, $aid = 0) { - $access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host')); - $edit = db_fetch_object(db_query('SELECT aid, type, status, mask FROM {access} WHERE aid = %d', $aid)); - - $form = array(); - $form['aid'] = array('#type' => 'hidden', '#value' => $aid); - $output = confirm_form($form, - t('Are you sure you want to delete the @type rule for %rule?', array('@type' => $access_types[$edit->type], '%rule' => $edit->mask)), - 'admin/user/rules', - t('This action cannot be undone.'), - t('Delete'), - t('Cancel')); - return $output; -} - -function user_admin_access_delete_confirm_submit($form, &$form_state) { - db_query('DELETE FROM {access} WHERE aid = %d', $form_state['values']['aid']); - drupal_set_message(t('The access rule has been deleted.')); - $form_state['redirect'] = 'admin/user/rules'; - return; -} - -/** - * Menu callback: list all access rules - */ -function user_admin_access() { - $header = array(array('data' => t('Access type'), 'field' => 'status'), array('data' => t('Rule type'), 'field' => 'type'), array('data' => t('Mask'), 'field' => 'mask'), array('data' => t('Operations'), 'colspan' => 2)); - $result = db_query("SELECT aid, type, status, mask FROM {access}". tablesort_sql($header)); - $access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host')); - $rows = array(); - while ($rule = db_fetch_object($result)) { - $rows[] = array($rule->status ? t('allow') : t('deny'), $access_types[$rule->type], $rule->mask, l(t('edit'), 'admin/user/rules/edit/'. $rule->aid), l(t('delete'), 'admin/user/rules/delete/'. $rule->aid)); - } - if (empty($rows)) { - $rows[] = array(array('data' => ''. t('There are currently no access rules.') .'', 'colspan' => 5)); - } - return theme('table', $header, $rows); -} - /** * Theme user administration overview. * diff --git a/modules/user/user.css b/modules/user/user.css index 977badd7083..44604982823 100644 --- a/modules/user/user.css +++ b/modules/user/user.css @@ -9,16 +9,6 @@ #permissions tr.odd .form-item, tr.even .form-item { white-space: normal; } -#access-rules .access-type, #access-rules .rule-type { - margin-right: 1em; /* LTR */ - float: left; /* LTR */ -} -#access-rules .access-type .form-item, #access-rules .rule-type .form-item { - margin-top: 0; -} -#access-rules .mask { - clear: both; -} #user-login-form { text-align: center; } diff --git a/modules/user/user.install b/modules/user/user.install index ac9527e164b..5f63f05ea87 100644 --- a/modules/user/user.install +++ b/modules/user/user.install @@ -5,39 +5,6 @@ * Implementation of hook_schema(). */ function user_schema() { - $schema['access'] = array( - 'description' => t('Stores site access rules.'), - 'fields' => array( - 'aid' => array( - 'type' => 'serial', - 'not null' => TRUE, - 'description' => t('Primary Key: Unique access ID.'), - ), - 'mask' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - 'description' => t('Text mask used for filtering access.'), - ), - 'type' => array( - 'type' => 'varchar', - 'length' => 255, - 'not null' => TRUE, - 'default' => '', - 'description' => t('Type of access rule: name, mail or host.'), - ), - 'status' => array( - 'type' => 'int', - 'not null' => TRUE, - 'default' => 0, - 'size' => 'tiny', - 'description' => t('Whether rule is to allow(1) or deny(0) access.'), - ), - ), - 'primary key' => array('aid'), - ); - $schema['authmap'] = array( 'description' => t('Stores distributed authentication mapping.'), 'fields' => array( diff --git a/modules/user/user.module b/modules/user/user.module index 9f4910146be..8e9d9a1866c 100644 --- a/modules/user/user.module +++ b/modules/user/user.module @@ -92,7 +92,7 @@ function user_external_load($authname) { * Perform standard Drupal login operations for a user object. * * The user object must already be authenticated. This function verifies - * that the user account is not blocked/denied and then performs the login, + * that the user account is not blocked and then performs the login, * updates the login timestamp in the database, invokes hook_user('login'), * and regenerates the session. * @@ -113,7 +113,7 @@ function user_external_login($account, $edit = array()) { $state['values']['name'] = $account->name; } - // Check if user is blocked or denied by access rules. + // Check if user is blocked. user_login_name_validate($form, $state, (array)$account); if (form_get_errors()) { // Invalid login. @@ -952,43 +952,6 @@ function user_menu() { 'type' => MENU_CALLBACK, 'file' => 'user.admin.inc', ); - $items['admin/user/rules'] = array( - 'title' => 'Access rules', - 'description' => 'List and create rules to disallow usernames, e-mail addresses, and IP addresses.', - 'page callback' => 'user_admin_access', - 'access arguments' => array('administer permissions'), - 'file' => 'user.admin.inc', - ); - $items['admin/user/rules/list'] = array( - 'title' => 'List', - 'type' => MENU_DEFAULT_LOCAL_TASK, - 'weight' => -10, - ); - $items['admin/user/rules/add'] = array( - 'title' => 'Add rule', - 'page callback' => 'user_admin_access_add', - 'type' => MENU_LOCAL_TASK, - 'file' => 'user.admin.inc', - ); - $items['admin/user/rules/check'] = array( - 'title' => 'Check rules', - 'page callback' => 'user_admin_access_check', - 'type' => MENU_LOCAL_TASK, - 'file' => 'user.admin.inc', - ); - $items['admin/user/rules/edit'] = array( - 'title' => 'Edit rule', - 'page callback' => 'user_admin_access_edit', - 'type' => MENU_CALLBACK, - 'file' => 'user.admin.inc', - ); - $items['admin/user/rules/delete'] = array( - 'title' => 'Delete rule', - 'page callback' => 'drupal_get_form', - 'page arguments' => array('user_admin_access_delete_confirm'), - 'type' => MENU_CALLBACK, - 'file' => 'user.admin.inc', - ); $items['logout'] = array( 'title' => 'Log out', @@ -1219,7 +1182,7 @@ function user_login(&$form_state, $msg = '') { } /** - * Set up a series for validators which check for blocked/denied users, + * Set up a series for validators which check for blocked users, * then authenticate against local database, then return an error if * authentication fails. Distributed authentication modules are welcome * to use hook_form_alter() to change this series in order to @@ -1240,8 +1203,7 @@ function user_login_default_validators() { } /** - * A FAPI validate handler. Sets an error if supplied username has been blocked - * or denied access. + * A FAPI validate handler. Sets an error if supplied username has been blocked. */ function user_login_name_validate($form, &$form_state) { if (isset($form_state['values']['name'])) { @@ -1249,10 +1211,6 @@ function user_login_name_validate($form, &$form_state) { // blocked in user administration form_set_error('name', t('The username %name has not been activated or is blocked.', array('%name' => $form_state['values']['name']))); } - else if (drupal_is_denied('user', $form_state['values']['name'])) { - // denied by access controls - form_set_error('name', t('The name %name is a reserved username.', array('%name' => $form_state['values']['name']))); - } } } @@ -1504,9 +1462,6 @@ function _user_edit_validate($uid, &$edit) { else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE uid != %d AND LOWER(name) = LOWER('%s')", $uid, $edit['name'])) > 0) { form_set_error('name', t('The name %name is already taken.', array('%name' => $edit['name']))); } - else if (drupal_is_denied('user', $edit['name'])) { - form_set_error('name', t('The name %name has been denied access.', array('%name' => $edit['name']))); - } } // Validate the e-mail address: @@ -1516,9 +1471,6 @@ function _user_edit_validate($uid, &$edit) { else if (db_result(db_query("SELECT COUNT(*) FROM {users} WHERE uid != %d AND LOWER(mail) = LOWER('%s')", $uid, $edit['mail'])) > 0) { form_set_error('mail', t('The e-mail address %email is already registered. Have you forgotten your password?', array('%email' => $edit['mail'], '@password' => url('user/password')))); } - else if (drupal_is_denied('mail', $edit['mail'])) { - form_set_error('mail', t('The e-mail address %email has been denied access.', array('%email' => $edit['mail']))); - } } function _user_edit_submit($uid, &$edit) { @@ -1853,8 +1805,6 @@ function user_help($path, $arg) { case 'admin/user/user/create': case 'admin/user/user/account/create': return '

'. t("This web page allows administrators to register new users. Users' e-mail addresses and usernames must be unique.") .'

'; - case 'admin/user/rules': - return '

'. t('Set up username and e-mail address access rules for new and existing accounts (currently logged in accounts will not be logged out). If a username or e-mail address for an account matches any deny rule, but not an allow rule, then the account will not be allowed to be created or to log in. A host rule is effective for every page view, not just registrations.') .'

'; case 'admin/user/permissions': return '

'. t('Permissions let you control what users can do on your site. Each user role (defined on the user roles page) has its own set of permissions. For example, you could give users classified as "Administrators" permission to "administer nodes" but deny this power to ordinary, "authenticated" users. You can use permissions to reveal new features to privileged users (those with subscriptions, for example). Permissions also allow trusted users to share the administrative burden of running a busy site.', array('@role' => url('admin/user/roles'))) .'

'; case 'admin/user/roles': @@ -2181,12 +2131,6 @@ function user_action_info() { 'configurable' => FALSE, 'hooks' => array(), ), - 'user_block_ip_action' => array( - 'description' => t('Ban IP address of current user'), - 'type' => 'user', - 'configurable' => FALSE, - 'hooks' => array(), - ), ); } @@ -2210,16 +2154,6 @@ function user_block_user_action(&$object, $context = array()) { watchdog('action', 'Blocked user %name.', array('%name' => check_plain($user->name))); } -/** - * Implementation of a Drupal action. - * Adds an access rule that blocks the user's IP address. - */ -function user_block_ip_action() { - $ip = ip_address(); - db_query("INSERT INTO {access} (mask, type, status) VALUES ('%s', '%s', %d)", $ip, 'host', 0); - watchdog('action', 'Banned IP address %ip', array('%ip' => $ip)); -} - /** * Submit handler for the user registration form. * diff --git a/sites/default/default.settings.php b/sites/default/default.settings.php index 5f531e62ff8..f2cef06a2a5 100644 --- a/sites/default/default.settings.php +++ b/sites/default/default.settings.php @@ -226,3 +226,26 @@ ini_set('url_rewriter.tags', ''); # 'forum' => 'Discussion board', # '@count min' => '@count minutes', # ); + +/** + * + * IP blocking: + * + * To bypass database queries for denied IP addresses, use this setting. + * Drupal queries the {blocked_ips} table by default on every page request + * for both authenticated and anonymous users. This allows the system to + * block IP addresses from within the administrative interface and before any + * modules are loaded. However on high traffic websites you may want to avoid + * this query, allowing you to bypass database access altogether for anonymous + * users under certain caching configurations. + * + * If using this setting, you will need to add back any IP addresses which + * you may have blocked via the administrative interface. Each element of this + * array represents a blocked IP address. Uncommenting the array and leaving it + * empty will have the effect of disabling IP blocking on your site. + * + * Remove the leading hash signs to enable. + */ +# $conf['blocked_ips'] = array( +# 'a.b.c.d', +# );