diff options
Diffstat (limited to 'modules/node/node.module')
-rw-r--r-- | modules/node/node.module | 59 |
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: |