1 /** 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the 7 * "License"); you may not use this file except in compliance 8 * with the License. You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 package org.apache.hadoop.hdfs.server.namenode; 19 20 import java.io.IOException; 21 import java.util.Arrays; 22 import java.util.Collections; 23 import java.util.HashSet; 24 import java.util.Set; 25 import java.util.Stack; 26 27 import org.apache.commons.logging.Log; 28 import org.apache.commons.logging.LogFactory; 29 import org.apache.hadoop.fs.permission.FsAction; 30 import org.apache.hadoop.fs.permission.FsPermission; 31 import org.apache.hadoop.security.AccessControlException; 32 import org.apache.hadoop.security.UserGroupInformation; 33 34 /** 35 * Class that helps in checking file system permission. 36 * The state of this class need not be synchronized as it has data structures that 37 * are read-only. 38 * 39 * Some of the helper methods are guarded by {@link FSNamesystem} intrinsic lock. 40 */ 41 class FSPermissionChecker { 42 static final Log LOG = LogFactory.getLog(UserGroupInformation.class); 43 44 private final UserGroupInformation ugi; 45 private final String user; 46 /** A set with group namess. Not synchronized since it is unmodifiable */ 47 private final Set<String> groups; 48 private final boolean isSuper; 49 FSPermissionChecker(String fsOwner, String supergroup )50 FSPermissionChecker(String fsOwner, String supergroup 51 ) throws AccessControlException{ 52 try { 53 ugi = UserGroupInformation.getCurrentUser(); 54 } catch (IOException e) { 55 throw new AccessControlException(e); 56 } 57 58 HashSet<String> s = new HashSet<String>(Arrays.asList(ugi.getGroupNames())); 59 groups = Collections.unmodifiableSet(s); 60 user = ugi.getShortUserName(); 61 isSuper = user.equals(fsOwner) || groups.contains(supergroup); 62 } 63 64 /** 65 * Check if the callers group contains the required values. 66 * @param group group to check 67 */ containsGroup(String group)68 public boolean containsGroup(String group) {return groups.contains(group);} 69 getUser()70 public String getUser() { 71 return user; 72 } 73 isSuperUser()74 public boolean isSuperUser() { 75 return isSuper; 76 } 77 78 /** 79 * Verify if the caller has the required permission. This will result into 80 * an exception if the caller is not allowed to access the resource. 81 */ checkSuperuserPrivilege()82 public void checkSuperuserPrivilege() 83 throws AccessControlException { 84 if (!isSuper) { 85 throw new AccessControlException("Access denied for user " 86 + user + ". Superuser privilege is required"); 87 } 88 } 89 90 /** 91 * Check whether current user have permissions to access the path. 92 * Traverse is always checked. 93 * 94 * Parent path means the parent directory for the path. 95 * Ancestor path means the last (the closest) existing ancestor directory 96 * of the path. 97 * Note that if the parent path exists, 98 * then the parent path and the ancestor path are the same. 99 * 100 * For example, suppose the path is "/foo/bar/baz". 101 * No matter baz is a file or a directory, 102 * the parent path is "/foo/bar". 103 * If bar exists, then the ancestor path is also "/foo/bar". 104 * If bar does not exist and foo exists, 105 * then the ancestor path is "/foo". 106 * Further, if both foo and bar do not exist, 107 * then the ancestor path is "/". 108 * 109 * @param doCheckOwner Require user to be the owner of the path? 110 * @param ancestorAccess The access required by the ancestor of the path. 111 * @param parentAccess The access required by the parent of the path. 112 * @param access The access required by the path. 113 * @param subAccess If path is a directory, 114 * it is the access required of the path and all the sub-directories. 115 * If path is not a directory, there is no effect. 116 * @throws AccessControlException 117 * 118 * Guarded by {@link FSNamesystem} intrinsic lock 119 * Caller of this method must hold that lock. 120 */ checkPermission(String path, INodeDirectory root, boolean doCheckOwner, FsAction ancestorAccess, FsAction parentAccess, FsAction access, FsAction subAccess)121 void checkPermission(String path, INodeDirectory root, boolean doCheckOwner, 122 FsAction ancestorAccess, FsAction parentAccess, FsAction access, 123 FsAction subAccess) throws AccessControlException { 124 if (LOG.isDebugEnabled()) { 125 LOG.debug("ACCESS CHECK: " + this 126 + ", doCheckOwner=" + doCheckOwner 127 + ", ancestorAccess=" + ancestorAccess 128 + ", parentAccess=" + parentAccess 129 + ", access=" + access 130 + ", subAccess=" + subAccess); 131 } 132 133 synchronized(root) { 134 INode[] inodes = root.getExistingPathINodes(path); 135 int ancestorIndex = inodes.length - 2; 136 for(; ancestorIndex >= 0 && inodes[ancestorIndex] == null; 137 ancestorIndex--); 138 checkTraverse(inodes, ancestorIndex); 139 140 if (ancestorAccess != null && inodes.length > 1) { 141 check(inodes, ancestorIndex, ancestorAccess); 142 } 143 if (parentAccess != null && inodes.length > 1) { 144 check(inodes, inodes.length - 2, parentAccess); 145 } 146 if (access != null) { 147 check(inodes[inodes.length - 1], access); 148 } 149 if (subAccess != null) { 150 checkSubAccess(inodes[inodes.length - 1], subAccess); 151 } 152 if (doCheckOwner) { 153 checkOwner(inodes[inodes.length - 1]); 154 } 155 } 156 } 157 158 /** Guarded by {@link FSNamesystem} intrinsic lock */ checkOwner(INode inode)159 private void checkOwner(INode inode) throws AccessControlException { 160 if (inode != null && user.equals(inode.getUserName())) { 161 return; 162 } 163 throw new AccessControlException("Permission denied"); 164 } 165 166 /** Guarded by {@link FSNamesystem} intrinsic lock */ checkTraverse(INode[] inodes, int last )167 private void checkTraverse(INode[] inodes, int last 168 ) throws AccessControlException { 169 for(int j = 0; j <= last; j++) { 170 check(inodes[j], FsAction.EXECUTE); 171 } 172 } 173 174 /** Guarded by {@link FSNamesystem} intrinsic lock */ checkSubAccess(INode inode, FsAction access )175 private void checkSubAccess(INode inode, FsAction access 176 ) throws AccessControlException { 177 if (inode == null || !inode.isDirectory()) { 178 return; 179 } 180 181 Stack<INodeDirectory> directories = new Stack<INodeDirectory>(); 182 for(directories.push((INodeDirectory)inode); !directories.isEmpty(); ) { 183 INodeDirectory d = directories.pop(); 184 check(d, access); 185 186 for(INode child : d.getChildren()) { 187 if (child.isDirectory()) { 188 directories.push((INodeDirectory)child); 189 } 190 } 191 } 192 } 193 194 /** Guarded by {@link FSNamesystem} intrinsic lock */ check(INode[] inodes, int i, FsAction access )195 private void check(INode[] inodes, int i, FsAction access 196 ) throws AccessControlException { 197 check(i >= 0? inodes[i]: null, access); 198 } 199 200 /** Guarded by {@link FSNamesystem} intrinsic lock */ check(INode inode, FsAction access )201 private void check(INode inode, FsAction access 202 ) throws AccessControlException { 203 if (inode == null) { 204 return; 205 } 206 FsPermission mode = inode.getFsPermission(); 207 208 if (user.equals(inode.getUserName())) { //user class 209 if (mode.getUserAction().implies(access)) { return; } 210 } 211 else if (groups.contains(inode.getGroupName())) { //group class 212 if (mode.getGroupAction().implies(access)) { return; } 213 } 214 else { //other class 215 if (mode.getOtherAction().implies(access)) { return; } 216 } 217 throw new AccessControlException("Permission denied: user=" + user 218 + ", access=" + access + ", inode=" + inode); 219 } 220 } 221