4545class FSPermissionChecker implements AccessControlEnforcer {
4646 static final Log LOG = LogFactory .getLog (UserGroupInformation .class );
4747
48+ private static String constructPath (INodeAttributes [] inodes , int end ) {
49+ byte [][] components = new byte [end +1 ][];
50+ for (int i =0 ; i <= end ; i ++) {
51+ components [i ] = inodes [i ].getLocalNameBytes ();
52+ }
53+ return DFSUtil .byteArray2PathString (components );
54+ }
55+
4856 /** @return a string for throwing {@link AccessControlException} */
4957 private String toAccessControlString (INodeAttributes inodeAttrib , String path ,
50- FsAction access , FsPermission mode ) {
51- return toAccessControlString (inodeAttrib , path , access , mode , false );
58+ FsAction access ) {
59+ return toAccessControlString (inodeAttrib , path , access , false );
5260 }
5361
5462 /** @return a string for throwing {@link AccessControlException} */
5563 private String toAccessControlString (INodeAttributes inodeAttrib ,
56- String path , FsAction access , FsPermission mode , boolean deniedFromAcl ) {
64+ String path , FsAction access , boolean deniedFromAcl ) {
5765 StringBuilder sb = new StringBuilder ("Permission denied: " )
5866 .append ("user=" ).append (getUser ()).append (", " )
5967 .append ("access=" ).append (access ).append (", " )
6068 .append ("inode=\" " ).append (path ).append ("\" :" )
6169 .append (inodeAttrib .getUserName ()).append (':' )
6270 .append (inodeAttrib .getGroupName ()).append (':' )
6371 .append (inodeAttrib .isDirectory () ? 'd' : '-' )
64- .append (mode );
72+ .append (inodeAttrib . getFsPermission () );
6573 if (deniedFromAcl ) {
6674 sb .append ("+" );
6775 }
@@ -112,6 +120,11 @@ public INodeAttributeProvider getAttributesProvider() {
112120 return attributeProvider ;
113121 }
114122
123+ private AccessControlEnforcer getAccessControlEnforcer () {
124+ return (attributeProvider != null )
125+ ? attributeProvider .getExternalAccessControlEnforcer (this ) : this ;
126+ }
127+
115128 /**
116129 * Verify if the caller has the required permission. This will result into
117130 * an exception if the caller is not allowed to access the resource.
@@ -174,77 +187,54 @@ void checkPermission(INodesInPath inodesInPath, boolean doCheckOwner,
174187 final int snapshotId = inodesInPath .getPathSnapshotId ();
175188 final INode [] inodes = inodesInPath .getINodesArray ();
176189 final INodeAttributes [] inodeAttrs = new INodeAttributes [inodes .length ];
177- final byte [][] pathByNameArr = new byte [ inodes . length ][] ;
190+ final byte [][] components = inodesInPath . getPathComponents () ;
178191 for (int i = 0 ; i < inodes .length && inodes [i ] != null ; i ++) {
179- if (inodes [i ] != null ) {
180- pathByNameArr [i ] = inodes [i ].getLocalNameBytes ();
181- inodeAttrs [i ] = getINodeAttrs (pathByNameArr , i , inodes [i ], snapshotId );
182- }
192+ inodeAttrs [i ] = getINodeAttrs (components , i , inodes [i ], snapshotId );
183193 }
184194
185195 String path = inodesInPath .getPath ();
186196 int ancestorIndex = inodes .length - 2 ;
187197
188- AccessControlEnforcer enforcer =
189- getAttributesProvider ().getExternalAccessControlEnforcer (this );
198+ AccessControlEnforcer enforcer = getAccessControlEnforcer ();
190199 enforcer .checkPermission (fsOwner , supergroup , callerUgi , inodeAttrs , inodes ,
191- pathByNameArr , snapshotId , path , ancestorIndex , doCheckOwner ,
200+ components , snapshotId , path , ancestorIndex , doCheckOwner ,
192201 ancestorAccess , parentAccess , access , subAccess , ignoreEmptyDir );
193202 }
194203
195- /**
196- * Check whether exception e is due to an ancestor inode's not being
197- * directory.
198- */
199- private void checkAncestorType (INode [] inodes , int checkedAncestorIndex ,
200- AccessControlException e ) throws AccessControlException {
201- for (int i = 0 ; i <= checkedAncestorIndex ; i ++) {
202- if (inodes [i ] == null ) {
203- break ;
204- }
205- if (!inodes [i ].isDirectory ()) {
206- throw new AccessControlException (
207- e .getMessage () + " (Ancestor " + inodes [i ].getFullPathName ()
208- + " is not a directory)." );
209- }
210- }
211- throw e ;
212- }
213-
214204 @ Override
215205 public void checkPermission (String fsOwner , String supergroup ,
216206 UserGroupInformation callerUgi , INodeAttributes [] inodeAttrs ,
217- INode [] inodes , byte [][] pathByNameArr , int snapshotId , String path ,
207+ INode [] inodes , byte [][] components , int snapshotId , String path ,
218208 int ancestorIndex , boolean doCheckOwner , FsAction ancestorAccess ,
219209 FsAction parentAccess , FsAction access , FsAction subAccess ,
220210 boolean ignoreEmptyDir )
221211 throws AccessControlException {
222212 for (; ancestorIndex >= 0 && inodes [ancestorIndex ] == null ;
223213 ancestorIndex --);
224214
225- checkTraverse (inodeAttrs , inodes , path , ancestorIndex );
215+ checkTraverse (inodeAttrs , ancestorIndex );
226216
227217 final INodeAttributes last = inodeAttrs [inodeAttrs .length - 1 ];
228218 if (parentAccess != null && parentAccess .implies (FsAction .WRITE )
229219 && inodeAttrs .length > 1 && last != null ) {
230- checkStickyBit (inodeAttrs [ inodeAttrs .length - 2 ], last , path );
220+ checkStickyBit (inodeAttrs , inodeAttrs .length - 2 );
231221 }
232222 if (ancestorAccess != null && inodeAttrs .length > 1 ) {
233- check (inodeAttrs , path , ancestorIndex , ancestorAccess );
223+ check (inodeAttrs , ancestorIndex , ancestorAccess );
234224 }
235225 if (parentAccess != null && inodeAttrs .length > 1 ) {
236- check (inodeAttrs , path , inodeAttrs .length - 2 , parentAccess );
226+ check (inodeAttrs , inodeAttrs .length - 2 , parentAccess );
237227 }
238228 if (access != null ) {
239- check (last , path , access );
229+ check (inodeAttrs , inodeAttrs . length - 1 , access );
240230 }
241231 if (subAccess != null ) {
242232 INode rawLast = inodes [inodeAttrs .length - 1 ];
243- checkSubAccess (pathByNameArr , inodeAttrs .length - 1 , rawLast ,
233+ checkSubAccess (components , inodeAttrs .length - 1 , rawLast ,
244234 snapshotId , subAccess , ignoreEmptyDir );
245235 }
246236 if (doCheckOwner ) {
247- checkOwner (last );
237+ checkOwner (inodeAttrs , inodeAttrs . length - 1 );
248238 }
249239 }
250240
@@ -262,32 +252,35 @@ private INodeAttributes getINodeAttrs(byte[][] pathByNameArr, int pathIdx,
262252 }
263253
264254 /** Guarded by {@link FSNamesystem#readLock()} */
265- private void checkOwner (INodeAttributes inode
266- ) throws AccessControlException {
267- if (getUser ().equals (inode .getUserName ())) {
255+ private void checkOwner (INodeAttributes [] inodes , int i )
256+ throws AccessControlException {
257+ if (getUser ().equals (inodes [ i ] .getUserName ())) {
268258 return ;
269259 }
270260 throw new AccessControlException (
271- "Permission denied. user="
272- + getUser () + " is not the owner of inode=" + inode );
261+ "Permission denied. user=" + getUser () +
262+ " is not the owner of inode=" + constructPath ( inodes , i ) );
273263 }
274264
275265 /** Guarded by {@link FSNamesystem#readLock()} */
276- private void checkTraverse (INodeAttributes [] inodeAttrs , INode [] inodes ,
277- String path , int last ) throws AccessControlException {
278- int j = 0 ;
279- try {
280- for (; j <= last ; j ++) {
281- check (inodeAttrs [j ], path , FsAction .EXECUTE );
266+ private void checkTraverse (INodeAttributes [] inodeAttrs , int last )
267+ throws AccessControlException {
268+ for (int i =0 ; i <= last ; i ++) {
269+ INodeAttributes inode = inodeAttrs [i ];
270+ if (!inode .isDirectory ()) {
271+ throw new AccessControlException (
272+ constructPath (inodeAttrs , i ) + " (is not a directory)" );
273+ }
274+ if (!hasPermission (inode , FsAction .EXECUTE )) {
275+ throw new AccessControlException (toAccessControlString (
276+ inode , constructPath (inodeAttrs , i ), FsAction .EXECUTE ));
282277 }
283- } catch (AccessControlException e ) {
284- checkAncestorType (inodes , j , e );
285278 }
286279 }
287280
288281 /** Guarded by {@link FSNamesystem#readLock()} */
289- private void checkSubAccess (byte [][] pathByNameArr , int pathIdx , INode inode ,
290- int snapshotId , FsAction access , boolean ignoreEmptyDir )
282+ private void checkSubAccess (byte [][] components , int pathIdx ,
283+ INode inode , int snapshotId , FsAction access , boolean ignoreEmptyDir )
291284 throws AccessControlException {
292285 if (inode == null || !inode .isDirectory ()) {
293286 return ;
@@ -299,8 +292,12 @@ private void checkSubAccess(byte[][] pathByNameArr, int pathIdx, INode inode,
299292 ReadOnlyList <INode > cList = d .getChildrenList (snapshotId );
300293 if (!(cList .isEmpty () && ignoreEmptyDir )) {
301294 //TODO have to figure this out with inodeattribute provider
302- check (getINodeAttrs (pathByNameArr , pathIdx , d , snapshotId ),
303- inode .getFullPathName (), access );
295+ INodeAttributes inodeAttr =
296+ getINodeAttrs (components , pathIdx , d , snapshotId );
297+ if (!hasPermission (inodeAttr , access )) {
298+ throw new AccessControlException (
299+ toAccessControlString (inodeAttr , d .getFullPathName (), access ));
300+ }
304301 }
305302
306303 for (INode child : cList ) {
@@ -312,37 +309,40 @@ private void checkSubAccess(byte[][] pathByNameArr, int pathIdx, INode inode,
312309 }
313310
314311 /** Guarded by {@link FSNamesystem#readLock()} */
315- private void check (INodeAttributes [] inodes , String path , int i , FsAction access
316- ) throws AccessControlException {
317- check (i >= 0 ? inodes [i ] : null , path , access );
312+ private void check (INodeAttributes [] inodes , int i , FsAction access )
313+ throws AccessControlException {
314+ INodeAttributes inode = (i >= 0 ) ? inodes [i ] : null ;
315+ if (inode != null && !hasPermission (inode , access )) {
316+ throw new AccessControlException (
317+ toAccessControlString (inode , constructPath (inodes , i ), access ));
318+ }
318319 }
319320
320- private void check (INodeAttributes inode , String path , FsAction access
321- ) throws AccessControlException {
321+ // return whether access is permitted. note it neither requires a path or
322+ // throws so the caller can build the path only if required for an exception.
323+ // very beneficial for subaccess checks!
324+ private boolean hasPermission (INodeAttributes inode , FsAction access ) {
322325 if (inode == null ) {
323- return ;
326+ return true ;
324327 }
325328 final FsPermission mode = inode .getFsPermission ();
326329 final AclFeature aclFeature = inode .getAclFeature ();
327330 if (aclFeature != null ) {
328331 // It's possible that the inode has a default ACL but no access ACL.
329332 int firstEntry = aclFeature .getEntryAt (0 );
330333 if (AclEntryStatusFormat .getScope (firstEntry ) == AclEntryScope .ACCESS ) {
331- checkAccessAcl (inode , path , access , mode , aclFeature );
332- return ;
334+ return hasAclPermission (inode , access , mode , aclFeature );
333335 }
334336 }
337+ final FsAction checkAction ;
335338 if (getUser ().equals (inode .getUserName ())) { //user class
336- if (mode .getUserAction ().implies (access )) { return ; }
337- }
338- else if (getGroups ().contains (inode .getGroupName ())) { //group class
339- if (mode .getGroupAction ().implies (access )) { return ; }
339+ checkAction = mode .getUserAction ();
340+ } else if (getGroups ().contains (inode .getGroupName ())) { //group class
341+ checkAction = mode .getGroupAction ();
342+ } else { //other class
343+ checkAction = mode .getOtherAction ();
340344 }
341- else { //other class
342- if (mode .getOtherAction ().implies (access )) { return ; }
343- }
344- throw new AccessControlException (
345- toAccessControlString (inode , path , access , mode ));
345+ return checkAction .implies (access );
346346 }
347347
348348 /**
@@ -368,15 +368,14 @@ else if (getGroups().contains(inode.getGroupName())) { //group class
368368 * @param aclFeature AclFeature of inode
369369 * @throws AccessControlException if the ACL denies permission
370370 */
371- private void checkAccessAcl (INodeAttributes inode , String path ,
372- FsAction access , FsPermission mode , AclFeature aclFeature )
373- throws AccessControlException {
371+ private boolean hasAclPermission (INodeAttributes inode ,
372+ FsAction access , FsPermission mode , AclFeature aclFeature ) {
374373 boolean foundMatch = false ;
375374
376375 // Use owner entry from permission bits if user is owner.
377376 if (getUser ().equals (inode .getUserName ())) {
378377 if (mode .getUserAction ().implies (access )) {
379- return ;
378+ return true ;
380379 }
381380 foundMatch = true ;
382381 }
@@ -397,7 +396,7 @@ private void checkAccessAcl(INodeAttributes inode, String path,
397396 FsAction masked = AclEntryStatusFormat .getPermission (entry ).and (
398397 mode .getGroupAction ());
399398 if (masked .implies (access )) {
400- return ;
399+ return true ;
401400 }
402401 foundMatch = true ;
403402 break ;
@@ -412,7 +411,7 @@ private void checkAccessAcl(INodeAttributes inode, String path,
412411 FsAction masked = AclEntryStatusFormat .getPermission (entry ).and (
413412 mode .getGroupAction ());
414413 if (masked .implies (access )) {
415- return ;
414+ return true ;
416415 }
417416 foundMatch = true ;
418417 }
@@ -421,17 +420,13 @@ private void checkAccessAcl(INodeAttributes inode, String path,
421420 }
422421
423422 // Use other entry if user was not denied by an earlier match.
424- if (!foundMatch && mode .getOtherAction ().implies (access )) {
425- return ;
426- }
427-
428- throw new AccessControlException (
429- toAccessControlString (inode , path , access , mode ));
423+ return !foundMatch && mode .getOtherAction ().implies (access );
430424 }
431425
432426 /** Guarded by {@link FSNamesystem#readLock()} */
433- private void checkStickyBit (INodeAttributes parent , INodeAttributes inode ,
434- String path ) throws AccessControlException {
427+ private void checkStickyBit (INodeAttributes [] inodes , int index )
428+ throws AccessControlException {
429+ INodeAttributes parent = inodes [index ];
435430 if (!parent .getFsPermission ().getStickyBit ()) {
436431 return ;
437432 }
@@ -441,6 +436,7 @@ private void checkStickyBit(INodeAttributes parent, INodeAttributes inode,
441436 return ;
442437 }
443438
439+ INodeAttributes inode = inodes [index + 1 ];
444440 // if this user is the file owner, return
445441 if (inode .getUserName ().equals (getUser ())) {
446442 return ;
@@ -449,9 +445,10 @@ private void checkStickyBit(INodeAttributes parent, INodeAttributes inode,
449445 throw new AccessControlException (String .format (
450446 "Permission denied by sticky bit: user=%s, path=\" %s\" :%s:%s:%s%s, " +
451447 "parent=\" %s\" :%s:%s:%s%s" , user ,
452- path , inode .getUserName (), inode .getGroupName (),
448+ constructPath (inodes , index + 1 ),
449+ inode .getUserName (), inode .getGroupName (),
453450 inode .isDirectory () ? "d" : "-" , inode .getFsPermission ().toString (),
454- path . substring ( 0 , path . length () - inode . toString (). length () - 1 ),
451+ constructPath ( inodes , index ),
455452 parent .getUserName (), parent .getGroupName (),
456453 parent .isDirectory () ? "d" : "-" , parent .getFsPermission ().toString ()));
457454 }
0 commit comments