package org.dcache.acl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import diskCacheV111.namespace.NameSpaceProvider;
import diskCacheV111.util.CacheException;
import diskCacheV111.util.PnfsId;
import dmg.cells.nucleus.CellCommandListener;
import org.dcache.acl.enums.RsType;
import org.dcache.acl.parser.ACEParser;
import org.dcache.auth.Subjects;
import org.dcache.namespace.FileAttribute;
import org.dcache.util.Args;
import org.dcache.vehicles.FileAttributes;
/**
* This component provides administration tool to manage ACLs
* (commands for setting and getting ACL of files/directories).
*
* There are two commands for administration ACLs of the files or directories:
* (1) set ACL (+ means ALLOW, - means DENY) :
* setfacl <pnfsId|globalPath> <subject>:<+|-><access_msk>[:<flags>] [ ... ]
* Example:
* setfacl /pnfs/desy.de/data/dteam/MyFile USER:3750:+rdx EVERYONE@:-w GROUP:4567:-rda
* (2) get ACL of file or directory
* Examples:
* getfacl /pnfs/desy.de/data/dteam/MyFile
* getfacl 000062981E06479F4174A51AE9E3AE48FFC1
*
* @author Irina Kozlova
* @version 16 Dec 2008
*
*/
public class AclAdmin
implements CellCommandListener
{
static final int ACE_MIN_format2 = 2;
static final int ACE_MAX_format2 = 5;
public static final String OPTION_HELP = "h";
private static final Logger _logger =
LoggerFactory.getLogger(AclAdmin.class);
private NameSpaceProvider _nameSpaceProvider;
public void setNameSpaceProvider(NameSpaceProvider provider)
{
_nameSpaceProvider = provider;
}
/**
* Command for getting ACL
* Examples :
* getfacl /pnfs/desy.de/data/dteam/MyFile
* getfacl 000062981E06479F4174A51AE9E3AE48FFC1
*
*/
public static final String hh_getfacl = "<pnfsId>|<globalPath> # get ACL";
public static final String fh_getfacl =
"getfacl <pnfsId>|<globalPath> \n" +
"Gets ACL of a resource (a file or directory) \n" +
"which is defined by its pnfsId or globalPath. \n" +
" \n" +
"Example: \n" +
" getfacl /pnfs/example.org/data/MyDir \n" +
" ACL: rsId = 00004EEFE7E59A3441198E7EB744B0D8BA54, rsType = DIR \n" +
" type = A, accessMsk = lfsD, who = USER, whoID = 12457 \n" +
" type = A, flags = f, accessMsk = lfd, who = USER, whoID = 87552 \n" +
" In extra format: \n" +
" USER:12457:+lfsD \n" +
" USER:87552:+lfd:f \n" +
" \n" +
"The extra format is suitable for the setfacl command. \n" +
"See the help for that command for more details.";
public String ac_getfacl_$_1(Args args)
throws ACLException, CacheException
{
if (args.argc() < 1) {
throw new IllegalArgumentException("Usage: getfacl <pnfsId>|<globalPath>");
}
PnfsId pnfsId = getPnfsId(args.argv(0));
FileAttributes attr =
_nameSpaceProvider.getFileAttributes(Subjects.ROOT, pnfsId,
EnumSet.of(FileAttribute.ACL));
ACL acl = attr.getAcl();
if (acl != null) {
return acl.toExtraFormat();
} else {
return "ACL for the object rsId = " + args.argv(0) + " does not exist.";
}
}
/**
* Command for setting ACL
*
* ace_spec format: <who>[:<who_id>]:<+|-><access_msk>[:<flags>] (+ means ALLOW, - means DENY)
*
* ace_spec examples: USER:6750:+rlx:fd EVERYONE@:-w USER:3550:+rlwfx:do GROUP:4352:+rlwfx
*
*/
public static final String hh_setfacl =
"<pnfsId|globalPath> <subject>:<+|-><access_msk>[:<flags>] [ ... ] # set a new ACL";
public static final String fh_setfacl =
"setfacl <ID> <ACE> [<ACE> ...] \n" +
"where \n"+
"<ID> is <pnfsId|globalPath> \n" +
"<ACE> is <subject>:<+|-><access_msk>[:<flags>] \n" +
" \n" +
"Sets a new ACL consisting of one or more ACEs to a resource (a file or directory), \n" +
"which is defined by its pnfsId or globalPath. \n" +
"Each ACE defines permissions to access this resource \n" +
"for a subject (a user or group of users). \n" +
"ACEs are space delimited and are ordered by significance, i.e., \n" +
"first match wins.\n" +
" \n" +
"Description of the <ACE> structure. \n" +
" \n" +
"The element <subject> defines the subject of the ACE and\n" +
"must be one of the following values: \n" +
" USER:<who_id> : user identified by the virtual user ID <who_id> \n" +
"GROUP:<who_id> : group identified by the virtual group ID <who_id> \n" +
" OWNER@ : user who owns the resource\n" +
" GROUP@ : group that owns the resource \n" +
" EVERYONE@ : world, including the owner and owning group\n" +
" ANONYMOUS@ : accessed without any authentication \n" +
"AUTHENTICATED@ : any authenticated user (opposite of ANONYMOUS) \n" +
" \n" +
"The element <access_msk> is a set of bits describing \n" +
"how correspondent permissions will be modified for users matching the <subject>.\n" +
"If <access_msk> is preceded by a '+' then corresponding operations are allowed.\n" +
"If it is preceded by a '-' then corresponding operations are disallowed.\n " +
"Some bits apply only if the <ID> is a file, some apply only if <ID> is a directory\n" +
"and some to both. \n"+
"If the <ID> is not the correct type then the bit is converted to appropriate one,\n" +
"as indicated in parentheses. \n" +
"The following access permissions may be used: \n" +
" r : Permission to read the data of a file (converted to 'l' if directory). \n" +
" l : Permission to list the contents of a directory (converted to 'r' if file). \n" +
" w : Permission to modify a file's data anywhere in the file's offset range.\n" +
" This includes the ability to write to any arbitrary offset and \n" +
" as a result to grow the file. (Converted to 'f' if directory).\n" +
" f : Permission to add a new file in a directory (converted to 'w' if file).\n" +
" a : The ability to modify a file's data, but only starting at EOF \n"+
" (converted to 's' if directory).\n" +
" s : Permission to create a subdirectory in a directory (converted to 'a' if file).\n" +
" x : Permission to execute a file or traverse a directory.\n" +
" d : Permission to delete the file or directory.\n" +
" D : Permission to delete a file or directory within a directory.\n" +
" n : Permission to read the named attributes of a file or to lookup \n" +
" the named attributes directory.\n" +
" N : Permission to write the named attributes of a file or \n" +
" to create a named attribute directory.\n" +
" t : The ability to read basic attributes (non-ACLs) of a file or directory.\n" +
" T : Permission to change the times associated with a file \n" +
" or directory to an arbitrary value.\n" +
" c : Permission to read the ACL.\n" +
" C : Permission to write the acl and mode attributes.\n" +
" o : Permission to write the owner and owner group attributes.\n" +
" \n" +
"To enable ACL inheritance, the optional element <flags> must be defined.\n" +
"Multiple bits may be specified as a simple concatenated list of letters.\n" +
"Order doesn't matter. \n" +
" f : Can be placed on a directory and indicates that this ACE \n" +
" should be added to each new file created.\n" +
" d : Can be placed on a directory and indicates that this ACE \n" +
" should be added to each new directory created.\n" +
" o : Can be placed on a directory and indicates that this ACE \n" +
" should be ignored for this directory.\n" +
" Any ACE that inherit from an ACE with 'o' flag set will not have the 'o' flag set.\n" +
" Therefore, ACEs with this bit set take effect only if they are inherited \n" +
" by newly created files or directories as specified by the above two flags.\n" +
" REMARK: If 'o' flag is present on an ACE, then \n" +
" either 'd' or 'f' (or both) must be present as well.\n" +
" \n" +
"Example: \n" +
"setfacl /pnfs/example.org/data/TestDir USER:3750:+lfs:d EVERYONE@:+l GROUP:8745:-s USER:3452:+D \n" +
" Permissions for TestDir are altered so: \n" +
" First ACE. User with id 3750 (USER:3750) is allowed to \n"+
" list directory contents (l), \n" +
" create files (f), \n"+
" create subdirectories (s), \n" +
" and these permissions will be inherited by all newly created \n" +
" subdirectories as well (d). \n" +
" Second ACE. Everyone (EVERYONE@) is allowed to \n"+
" list directory contents. \n" +
" Third ACE. Group with id 8745 (GROUP:8745) is not allowed to \n" +
" create subdirectories.\n" +
" Fourth ACE. User with id 3452 (USER:3452) is allowed to \n" +
" delete objects within this directory (D). The user must also have \n" +
" the delete permission (d) for the object to be deleted. See next example.\n " +
" \n" +
"setfacl /pnfs/example.org/data/TestDir/TestFile USER:3452:+d \n" +
" Permissions for TestFile are altered so: \n" +
" First ACE. User with id 3452 (USER:3452) is allowed to \n" +
" delete this resource (d). To delete TestFile, the user must also \n"+
" have permission to delete directory contents (D). See previous example.\n" +
" \n" +
"For further information on ACLs in dCache please refer to: \n" +
"http://trac.dcache.org/trac.cgi/wiki/Integrate";
public String ac_setfacl_$_2_99(Args args)
throws CacheException, IllegalArgumentException
{
if (args.argc() < 2) {
throw new IllegalArgumentException("Usage : setfacl <pnfsid|globalPath> <who>[:<who_id>]:<+|-><access_msk>[:<flags>] [ ... ] ");
}
PnfsId pnfsId = getPnfsId(args.argv(0));
RsType rsType = getRsType(pnfsId);
// get list of ACEs
List<ACE> aces = new ArrayList<>();
for (int i = 1; i < args.argc(); i++) {
String ace_spec_format2 = args.argv(i);
ACE ace = ACEParser.parseAdmACE(ace_spec_format2);
if ( ace == null ) {
throw new IllegalArgumentException("Can't parse provided ACE: " + ace_spec_format2);
}
aces.add(ace);
}
ACL acl = new ACL(rsType, aces);
_nameSpaceProvider.setFileAttributes(Subjects.ROOT, pnfsId, FileAttributes.ofAcl(acl),
EnumSet.noneOf(FileAttribute.class));
return "Done";
}
private PnfsId getPnfsId(String s)
throws CacheException
{
if (PnfsId.isValid(s)) {
return new PnfsId(s);
} else {
return _nameSpaceProvider.pathToPnfsid(Subjects.ROOT, s, true);
}
}
private RsType getRsType(PnfsId pnfsId)
throws CacheException
{
FileAttributes attributes =
_nameSpaceProvider.getFileAttributes(Subjects.ROOT, pnfsId,
EnumSet.of(FileAttribute.TYPE));
switch (attributes.getFileType()) {
case DIR:
return RsType.DIR;
case REGULAR:
return RsType.FILE;
}
return null;
}
}