diff -urpN drupal-6.x-dev-200708270329/includes/bootstrap.inc drupal-6.x-dev-access-0.5/includes/bootstrap.inc
--- drupal-6.x-dev-200708270329/includes/bootstrap.inc 2007-08-27 00:00:29.000000000 +0800
+++ drupal-6.x-dev-access-0.5/includes/bootstrap.inc 2007-08-27 14:22:15.000000000 +0800
@@ -403,6 +403,148 @@ function drupal_get_filename($type, $nam
}
/**
+ * Load the persistent access table.
+ *
+ * The access table is composed of values that have been saved in the table
+ * with access_set().
+ */
+function access_init() {
+ // NOTE: caching the access rules improves performance by 5% when serving cached pages.
+ $accesses = array();
+ if ($cached = cache_get('accesses', 'cache')) {
+ $accesses = $cached->data;
+ }
+ else {
+ $result = db_query('SELECT * FROM {access}');
+
+ // Classify, group and preprocess fetched access rules.
+ while ($rule = db_fetch_object($result)) {
+ // Mask is not starting with '^': in plain text format. Escape it
+ // with preg_quote().
+ if (substr($rule->mask, 0, 1) != '^') {
+ $plain[$rule->type][$rule->status][] = '^' . preg_quote($rule->mask) . '$';
+ }
+ // Mask is starting with '^': in regex expression. Use directly without
+ // additional processing.
+ else {
+ $regex[$rule->type][$rule->status][] = $rule->mask;
+ }
+
+ // Record which type of rules are existing.
+ $record[$rule->type][$rule->status] = TRUE;
+ }
+
+ // Build regex expression for caching.
+ foreach ((array) $record as $type => $tmp) {
+ foreach ($tmp as $status => $mask) {
+ // NOTE: non-regexp matches are always done first.
+ $rules = array_merge((array) $plain[$type][$status], (array) $regex[$type][$status]);
+ $accesses[$type][$status] = '/' . implode('|', $rules) . '/Ds';
+ }
+ }
+
+ cache_set('accesses', $accesses);
+ }
+
+ return $accesses;
+}
+
+/**
+ * Return a persistent access rule checking result.
+ *
+ * @param $type
+ * Type of access to check.
+ * @param $mask
+ * String or mask to test.
+ * @param $order
+ * Controls the default access state and the order in which Allow and Deny
+ * are evaluated. Handle in Apache mod_authz_host style.
+ * @return
+ * TRUE if access is allowed, FALSE if access is denied.
+ */
+function access_get($type, $mask, $order = 'deny,allow') {
+ global $access;
+
+ switch (strtolower($order)) {
+ case 'allow,deny':
+ case 'mutual-failure':
+ // First, all Allow directives are evaluated; at least one must match,
+ // or the request is rejected. Next, all Deny directives are evaluated.
+ // If any matches, the request is rejected. Last, any requests which do
+ // not match an Allow or a Deny directive are denied by default.
+ $allow = FALSE;
+ if (isset($access[$type][1]) && $access[$type][1]) {
+ if (preg_match($access[$type][1], $mask)) {
+ $allow = TRUE;
+ }
+ }
+ if (isset($access[$type][0]) && $access[$type][0]) {
+ if (preg_match($access[$type][0], $mask)) {
+ $allow = FALSE;
+ }
+ }
+ break;
+ case 'deny,allow':
+ default:
+ // First, all Deny directives are evaluated; if any match, the request
+ // is denied unless it also matches an Allow directive. Any requests
+ // which do not match any Allow or Deny directives are permitted.
+ $allow = TRUE;
+ if (isset($access[$type][0]) && $access[$type][0]) {
+ if (preg_match($access[$type][0], $mask)) {
+ $allow = FALSE;
+ }
+ }
+ if (isset($access[$type][1]) && $access[$type][1]) {
+ if (preg_match($access[$type][1], $mask)) {
+ $allow = TRUE;
+ }
+ }
+ break;
+ }
+
+ return $allow;
+}
+
+/**
+ * Set a persistent access rule.
+ *
+ * @param $type
+ * Type of access to set.
+ * @param $mask
+ * String or mask to set.
+ * @param $status
+ * Status of access to set.
+ * @param $aid
+ * Access rule ID to alter.
+ */
+function access_set($type, $mask, $status, $aid = 0) {
+ if ($aid) {
+ db_query("UPDATE {access} SET mask = '%s', type = '%s', status = '%s' WHERE aid = %d", $mask, $type, $status, $aid);
+ if (!db_affected_rows()) {
+ $aid = 0;
+ }
+ }
+
+ if ($aid == 0) {
+ db_query("INSERT INTO {access} (mask, type, status) VALUES ('%s', '%s', %d)", $mask, $type, $status);
+ }
+
+ cache_clear_all('accesses', 'cache');
+}
+
+/**
+ * Unset a persistent access rule.
+ *
+ * @param $aid
+ * Access rule ID to alter.
+ */
+function access_del($aid) {
+ db_query('DELETE FROM {access} WHERE aid = %d', $aid);
+ cache_clear_all('accesses', 'cache');
+}
+
+/**
* Load the persistent variable table.
*
* The variable table is composed of values that have been saved in the table
@@ -792,40 +934,6 @@ function drupal_get_messages($type = NUL
}
/**
- * Perform an access check for a given mask and rule type. Rules are usually
- * created via admin/user/rules page.
- *
- * If any allow rule matches, access is allowed. Otherwise, if any deny rule
- * matches, access is denied. If no rule matches, access is allowed.
- *
- * @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.
- * @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. If any have status 1, or if there are no matching records,
- // we allow access. So, select matching records in decreasing order of
- // 'status', returning NOT(status) for the first. If any have status 1,
- // they come first, and we return NOT(status) = 0 (allowed). Otherwise,
- // if we have some with status 0, we return 1 (denied). If no matching
- // records, we get no return from db_result, so we return (bool)NULL = 0
- // (allowed).
- // The use of ORDER BY / LIMIT is more efficient than "MAX(status) = 0"
- // in PostgreSQL <= 8.0.
- return (bool) db_result(db_query_range("SELECT CASE WHEN status=1 THEN 0 ELSE 1 END FROM {access} WHERE type = '%s' AND LOWER(mask) LIKE LOWER('%s') ORDER BY status DESC", $type, $mask, 0, 1));
-}
-
-/**
* Generates a default anonymous $user object.
*
* @return Object - the user object.
@@ -878,7 +986,7 @@ function drupal_bootstrap($phase) {
}
function _drupal_bootstrap($phase) {
- global $conf;
+ global $access, $conf;
switch ($phase) {
@@ -899,8 +1007,11 @@ function _drupal_bootstrap($phase) {
break;
case DRUPAL_BOOTSTRAP_ACCESS:
+ // Initialize the access strategy.
+ $access = access_init();
+
// Deny access to hosts which were banned - t() is not yet available.
- if (drupal_is_denied('host', ip_address())) {
+ if (!access_get('host', ip_address())) {
header('HTTP/1.1 403 Forbidden');
print 'Sorry, '. check_plain(ip_address()) .' has been banned.';
exit();
diff -urpN drupal-6.x-dev-200708270329/modules/user/user.module drupal-6.x-dev-access-0.5/modules/user/user.module
--- drupal-6.x-dev-200708270329/modules/user/user.module 2007-08-26 16:00:49.000000000 +0800
+++ drupal-6.x-dev-access-0.5/modules/user/user.module 2007-08-27 13:14:23.000000000 +0800
@@ -1194,7 +1194,7 @@ function user_login_name_validate($form,
// 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'])) {
+ else if (!access_get('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'])));
}
@@ -1663,7 +1663,7 @@ function _user_edit_validate($uid, &$edi
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'])) {
+ else if (!access_get('user', $edit['name'])) {
form_set_error('name', t('The name %name has been denied access.', array('%name' => $edit['name'])));
}
}
@@ -1675,7 +1675,7 @@ function _user_edit_validate($uid, &$edi
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'])) {
+ else if (!access_get('mail', $edit['mail'])) {
form_set_error('mail', t('The e-mail address %email has been denied access.', array('%email' => $edit['mail'])));
}
}
@@ -1963,7 +1963,7 @@ function user_admin_access_check_validat
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'])) {
+ if (!access_get('user', $form_state['values']['test'])) {
drupal_set_message(t('The username %name is not allowed.', array('%name' => $form_state['values']['test'])));
}
else {
@@ -1971,7 +1971,7 @@ function user_admin_access_check_submit(
}
break;
case 'mail':
- if (drupal_is_denied('mail', $form_state['values']['test'])) {
+ if (!access_get('mail', $form_state['values']['test'])) {
drupal_set_message(t('The e-mail address %mail is not allowed.', array('%mail' => $form_state['values']['test'])));
}
else {
@@ -1979,7 +1979,7 @@ function user_admin_access_check_submit(
}
break;
case 'host':
- if (drupal_is_denied('host', $form_state['values']['test'])) {
+ if (!access_get('host', $form_state['values']['test'])) {
drupal_set_message(t('The hostname %host is not allowed.', array('%host' => $form_state['values']['test'])));
}
else {
@@ -2000,8 +2000,7 @@ function user_admin_access_add($mask = N
form_set_error('mask', t('You must enter a mask.'));
}
else {
- db_query("INSERT INTO {access} (aid, mask, type, status) VALUES ('%s', '%s', '%s', %d)", $aid, $edit['mask'], $edit['type'], $edit['status']);
- $aid = db_last_insert_id('access', 'aid');
+ access_set($edit['type'], $edit['mask'], $edit['status']);
drupal_set_message(t('The access rule has been added.'));
drupal_goto('admin/user/rules');
}
@@ -2032,7 +2031,7 @@ function user_admin_access_delete_confir
}
function user_admin_access_delete_confirm_submit($form, &$form_state) {
- db_query('DELETE FROM {access} WHERE aid = %d', $form_state['values']['aid']);
+ access_del($form_state['values']['aid']);
drupal_set_message(t('The access rule has been deleted.'));
$form_state['redirect'] = 'admin/user/rules';
return;
@@ -2047,7 +2046,7 @@ function user_admin_access_edit($aid = 0
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);
+ access_set($edit['type'], $edit['mask'], $edit['status'], $aid);
drupal_set_message(t('The access rule has been saved.'));
drupal_goto('admin/user/rules');
}
@@ -2078,7 +2077,7 @@ function user_admin_access_form(&$form_s
'#size' => 30,
'#maxlength' => 64,
'#default_value' => $edit['mask'],
- '#description' => '%: '. t('Matches any number of characters, even zero characters') .'.
_: '. t('Matches exactly one character.'),
+ '#description' => t('Start the line with a ^ character to designate a regular expression match.') . '
' . t('NOTE: non-regexp matches are always done first.'),
'#required' => TRUE,
);
$form['submit'] = array('#type' => 'submit', '#value' => $submit);
@@ -2091,7 +2090,7 @@ function user_admin_access_form(&$form_s
*/
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));
+ $result = db_query("SELECT aid, type, status, mask FROM {access} WHERE type = '%s' OR type = '%s' OR type = '%s'". tablesort_sql($header), 'host', 'mail', 'user');
$access_types = array('user' => t('username'), 'mail' => t('e-mail'), 'host' => t('host'));
$rows = array();
while ($rule = db_fetch_object($result)) {