summaryrefslogtreecommitdiff
path: root/modules/node/node.module
diff options
context:
space:
mode:
Diffstat (limited to 'modules/node/node.module')
-rw-r--r--modules/node/node.module59
1 files changed, 52 insertions, 7 deletions
diff --git a/modules/node/node.module b/modules/node/node.module
index 524a57fa7..4a11ff79c 100644
--- a/modules/node/node.module
+++ b/modules/node/node.module
@@ -3109,7 +3109,7 @@ function node_access_view_all_nodes($account = NULL) {
* 'update' and 'delete').
*/
function node_query_node_access_alter(QueryAlterableInterface $query) {
- _node_query_node_access_alter($query, 'node', 'node');
+ _node_query_node_access_alter($query, 'node');
}
/**
@@ -3120,7 +3120,7 @@ function node_query_node_access_alter(QueryAlterableInterface $query) {
* conditions are added for field values belonging to nodes only.
*/
function node_query_entity_field_access_alter(QueryAlterableInterface $query) {
- _node_query_node_access_alter($query, $query->getMetaData('base_table'), 'entity');
+ _node_query_node_access_alter($query, 'entity');
}
/**
@@ -3128,14 +3128,12 @@ function node_query_entity_field_access_alter(QueryAlterableInterface $query) {
*
* @param $query
* The query to add conditions to.
- * @param $base_table
- * The table holding node ids.
* @param $type
* Either 'node' or 'entity' depending on what sort of query it is. See
* node_query_node_access_alter() and node_query_entity_field_access_alter()
* for more.
*/
-function _node_query_node_access_alter($query, $base_table, $type) {
+function _node_query_node_access_alter($query, $type) {
global $user;
// Read meta-data from query, if provided.
@@ -3159,14 +3157,61 @@ function _node_query_node_access_alter($query, $base_table, $type) {
return;
}
+ $tables = $query->getTables();
+ $base_table = $query->getMetaData('base_table');
+ // If no base table is specified explicitly, search for one.
+ if (!$base_table) {
+ $fallback = '';
+ foreach ($tables as $alias => $table_info) {
+ if (!($table_info instanceof SelectQueryInterface)) {
+ $table = $table_info['table'];
+ // If the node table is in the query, it wins immediately.
+ if ($table == 'node') {
+ $base_table = $table;
+ break;
+ }
+ // Check whether the table has a foreign key to node.nid. If it does,
+ // do not run this check again as we found a base table and only node
+ // can triumph that.
+ if (!$base_table) {
+ // The schema is cached.
+ $schema = drupal_get_schema($table);
+ if (isset($schema['fields']['nid'])) {
+ if (isset($schema['foreign keys'])) {
+ foreach ($schema['foreign keys'] as $relation) {
+ if ($relation['table'] === 'node' && $relation['columns'] === array('nid' => 'nid')) {
+ $base_table = $table;
+ }
+ }
+ }
+ else {
+ // At least it's a nid. A table with a field called nid is very
+ // very likely to be a node.nid in a node access query.
+ $fallback = $table;
+ }
+ }
+ }
+ }
+ }
+ // If there is nothing else, use the fallback.
+ if (!$base_table) {
+ if ($fallback) {
+ watchdog('security', 'Your node listing query is using @fallback as a base table in a query tagged for node access. This might not be secure and might not even work. Specify foreign keys in your schema to node.nid ', array('@fallback' => $fallback), WATCHDOG_WARNING);
+ $base_table = $fallback;
+ }
+ else {
+ throw new Exception(t('Query tagged for node access but there is no nid. Add foreign keys to node.nid in schema to fix.'));
+ }
+ }
+ }
+
// Prevent duplicate records.
$query->distinct();
- // Find all instances of the {node} table being joined -- could appear
+ // Find all instances of the base table being joined -- could appear
// more than once in the query, and could be aliased. Join each one to
// the node_access table.
- $tables = $query->getTables();
$grants = node_access_grants($op, $account);
if ($type == 'entity') {
// The original query looked something like: