modules/comment/comment.module | 9 +++++ modules/file/file.module | 76 +++++++++++++++++++++++++--------------- modules/node/node.module | 9 +++++ modules/user/user.module | 9 +++++ 4 files changed, 75 insertions(+), 28 deletions(-) diff --git modules/comment/comment.module modules/comment/comment.module index 5bcba71..d3d67ea 100644 --- modules/comment/comment.module +++ modules/comment/comment.module @@ -2631,3 +2631,12 @@ function comment_rdf_mapping() { ), ); } + +/** + * Implements hook_file_download_access(). + */ +function comment_file_download_access($field, $entity_type, $entity) { + if ($entity_type == 'comment') { + return user_access('access comments') && $entity->status || user_access('administer comments'); + } +} diff --git modules/file/file.module modules/file/file.module index cfdb212..1b2f4f2 100644 --- modules/file/file.module +++ modules/file/file.module @@ -134,46 +134,66 @@ function file_file_download($uri, $field_type = 'file') { // Find out which (if any) file fields contain this file. $references = file_get_file_references($file, NULL, FIELD_LOAD_REVISION, $field_type); - // TODO: Check field-level access if available here. - - $denied = $file->status ? NULL : FALSE; - // Check access to content containing the file fields. If access is allowed - // to any of this content, allow the download. + // Default to allow access. + $denied = FALSE; + // Loop through all references of this file. If a reference explicitly allows + // access to the field to which this file belongs, no further checks are done + // and download access is granted. If a reference denies access, eventually + // existing additional references are checked. If all references were checked + // and no reference denied access, access is granted as well. If at least one + // reference denied access, access is denied. foreach ($references as $field_name => $field_references) { foreach ($field_references as $entity_type => $type_references) { - foreach ($type_references as $reference) { - // If access is allowed to any object, immediately stop and grant - // access. If access is denied, continue through in case another object - // grants access. - // TODO: Switch this to a universal access check mechanism if available. - if ($entity_type == 'node' && ($node = node_load($reference->nid))) { - if (node_access('view', $node)) { - $denied = FALSE; - break 3; + foreach ($type_references as $id => $reference) { + // Try to load $entity and $field. + $entity = reset(entity_load($entity_type, array($id))); + $field = NULL; + if ($entity) { + // Load all fields for that entity. + $field_items = field_get_items($entity_type, $entity, $field_name); + + // Find the field item with the matching URI. + foreach ($field_items as $field_item) { + if ($field_item['uri'] == $uri) { + $field = $field_item; + break; + } } - else { + } + + // Check that $entity and $field were loaded successfully and check if + // access to that field is not disallowed. If any of these checks fail, + // stop checking access for this reference. + if (empty($entity) || empty($field) || !field_access('view', $field, $entity_type, $entity)) { + $denied = TRUE; + break; + } + + // If access is not denied to this field, check if the user can view + // the entity. + foreach (module_implements('file_download_access') as $module) { + $function = $module . '_file_download_access'; + $return = $function($field, $entity_type, $entity); + // If an implementation returns FALSE, access to this entity is denied + // but the file could belong to another entity to which the user might + // have access. Continue with these. + if ($return === FALSE) { $denied = TRUE; + break 2; } - } - if ($entity_type == 'user') { - if (user_access('access user profiles') || $user->uid == $reference->uid) { + // If TRUE is returned, access is granted and no further checks are + // necessary. + if ($return === TRUE) { $denied = FALSE; - break 3; - } - else { - $denied = TRUE; + break 4; } } } } } - // No access was denied or granted. - if (!isset($denied)) { - return; - } - // Access specifically denied and not granted elsewhere. - elseif ($denied == TRUE) { + // Access specifically denied. + if ($denied) { return -1; } diff --git modules/node/node.module modules/node/node.module index 1b73b9c..b0fba0b 100644 --- modules/node/node.module +++ modules/node/node.module @@ -3686,3 +3686,12 @@ class NodeController extends DrupalDefaultEntityController { return $query; } } + +/** + * Implements hook_file_download_access(). + */ +function node_file_download_access($field, $entity_type, $entity) { + if ($entity_type == 'node') { + return node_access('view', $entity); + } +} diff --git modules/user/user.module modules/user/user.module index e042a41..c2cd1db 100644 --- modules/user/user.module +++ modules/user/user.module @@ -3678,3 +3678,12 @@ function user_rdf_mapping() { ), ); } + +/** + * Implements hook_file_download_access(). + */ +function user_file_download_access($field, $entity_type, $entity) { + if ($entity_type == 'user') { + return user_view_access($entity); + } +}