package org.dcache.namespace;
import javax.security.auth.Subject;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;
import org.dcache.acl.enums.AccessType;
import org.dcache.auth.Subjects;
import org.dcache.vehicles.FileAttributes;
import static org.dcache.acl.enums.AccessType.ACCESS_ALLOWED;
import static org.dcache.acl.enums.AccessType.ACCESS_DENIED;
import static org.dcache.chimera.UnixPermission.*;
import static org.dcache.namespace.FileAttribute.*;
/**
* A PermissionHandler implementing the POSIX.1 permission model.
*
* Notice that there is no concept of a ROOT owner in this
* PermissionHandler. That is, ROOT is just a regular user.
*/
public class PosixPermissionHandler implements PermissionHandler
{
private static final Set<FileAttribute> REQUIRED_ATTRIBUTES =
Collections.unmodifiableSet(EnumSet.of(OWNER, OWNER_GROUP, MODE));
@Override
public Set<FileAttribute> getRequiredAttributes()
{
return REQUIRED_ATTRIBUTES;
}
private boolean isSet(int mode, int flag)
{
return (mode & flag) == flag;
}
@Override
public AccessType canReadFile(Subject subject, FileAttributes attr)
{
int mode = attr.getMode();
if (Subjects.hasUid(subject, attr.getOwner())) {
return AccessType.valueOf(isSet(mode, S_IRUSR));
}
if (Subjects.hasGid(subject, attr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IRGRP));
}
return AccessType.valueOf(isSet(mode, S_IROTH));
}
@Override
public AccessType canWriteFile(Subject subject, FileAttributes attr)
{
int mode = attr.getMode();
if (Subjects.hasUid(subject, attr.getOwner())) {
return AccessType.valueOf(isSet(mode, S_IWUSR));
}
if (Subjects.hasGid(subject, attr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IWGRP));
}
return AccessType.valueOf(isSet(mode, S_IWOTH));
}
@Override
public AccessType canCreateSubDir(Subject subject, FileAttributes parentAttr)
{
if (parentAttr == null) {
return ACCESS_DENIED;
}
int mode = parentAttr.getMode();
if (Subjects.hasUid(subject, parentAttr.getOwner())) {
return AccessType.valueOf(isSet(mode, S_IWUSR | S_IXUSR));
}
if (Subjects.hasGid(subject, parentAttr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IWGRP | S_IXGRP));
}
return AccessType.valueOf(isSet(mode, S_IWOTH | S_IXOTH));
}
@Override
public AccessType canCreateFile(Subject subject, FileAttributes parentAttr)
{
if (parentAttr == null) {
return ACCESS_DENIED;
}
int mode = parentAttr.getMode();
if (Subjects.hasUid(subject, parentAttr.getOwner())) {
return AccessType.valueOf(isSet(mode, S_IWUSR | S_IXUSR));
}
if (Subjects.hasGid(subject, parentAttr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IWGRP | S_IXGRP));
}
return AccessType.valueOf(isSet(mode, S_IWOTH | S_IXOTH));
}
@Override
public AccessType canDeleteFile(Subject subject,
FileAttributes parentAttr,
FileAttributes childAttr)
{
if (parentAttr == null) {
return ACCESS_DENIED;
}
int mode = parentAttr.getMode();
if (Subjects.hasUid(subject, parentAttr.getOwner())) {
return AccessType.valueOf(isSet(mode, S_IWUSR | S_IXUSR));
}
if (Subjects.hasGid(subject, parentAttr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IWGRP | S_IXGRP));
}
return AccessType.valueOf(isSet(mode, S_IWOTH | S_IXOTH));
}
@Override
public AccessType canDeleteDir(Subject subject,
FileAttributes parentAttr,
FileAttributes childAttr)
{
if (parentAttr == null) {
return ACCESS_DENIED;
}
int mode = parentAttr.getMode();
if (Subjects.hasUid(subject, parentAttr.getOwner())) {
return AccessType.valueOf(isSet(mode, S_IWUSR | S_IXUSR));
}
if (Subjects.hasGid(subject, parentAttr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IWGRP | S_IXGRP));
}
return AccessType.valueOf(isSet(mode, S_IWOTH | S_IXOTH));
}
@Override
public AccessType canListDir(Subject subject, FileAttributes attr)
{
int mode = attr.getMode();
if (Subjects.hasUid(subject, attr.getOwner())) {
return AccessType.valueOf(isSet(mode, S_IRUSR | S_IXUSR));
}
if (Subjects.hasGid(subject, attr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IRGRP | S_IXGRP));
}
return AccessType.valueOf(isSet(mode, S_IROTH | S_IXOTH));
}
@Override
public AccessType canLookup(Subject subject, FileAttributes attr)
{
int mode = attr.getMode();
if (Subjects.hasUid(subject, attr.getOwner())) {
return AccessType.valueOf(isSet(mode, S_IXUSR));
}
if (Subjects.hasGid(subject, attr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IXGRP));
}
return AccessType.valueOf(isSet(mode, S_IXOTH));
}
@Override
public AccessType canRename(Subject subject,
FileAttributes parentAttr,
FileAttributes newParentAttr,
boolean isDirectory)
{
if (parentAttr == null || newParentAttr == null) {
return ACCESS_DENIED;
}
int parentMode = parentAttr.getMode();
int newParentMode = newParentAttr.getMode();
AccessType result;
if (Subjects.hasUid(subject, parentAttr.getOwner())) {
result = AccessType.valueOf(isSet(parentMode, S_IWUSR | S_IXUSR));
} else if (Subjects.hasGid(subject, parentAttr.getGroup())) {
result = AccessType.valueOf(isSet(parentMode, S_IWGRP | S_IXGRP));
} else {
result = AccessType.valueOf(isSet(parentMode, S_IWOTH | S_IXOTH));
}
if (result != ACCESS_ALLOWED) {
return ACCESS_DENIED;
}
if (Subjects.hasUid(subject, newParentAttr.getOwner())) {
return AccessType.valueOf(isSet(newParentMode, S_IWUSR | S_IXUSR));
} else if (Subjects.hasGid(subject, newParentAttr.getGroup())) {
return AccessType.valueOf(isSet(newParentMode, S_IWGRP | S_IXGRP));
}
return AccessType.valueOf(isSet(newParentMode, S_IWOTH | S_IXOTH));
}
@Override
public AccessType canSetAttributes(Subject subject,
FileAttributes attr,
Set<FileAttribute> attributes)
{
/* Some flags can only be changed by the owner of the file.
*/
if (attributes.contains(OWNER) ||
attributes.contains(OWNER_GROUP) ||
attributes.contains(MODE) ||
attributes.contains(ACL) ) {
if (!Subjects.hasUid(subject, attr.getOwner())) {
return AccessType.ACCESS_DENIED;
}
}
/* Other flags can be changed by whoever got write permission.
*/
int mode = attr.getMode();
if (Subjects.hasUid(subject, attr.getOwner())) {
// posix allows owner of file to set any attribute.
return AccessType.ACCESS_ALLOWED;
}
if (Subjects.hasGid(subject, attr.getGroup())) {
return AccessType.valueOf(isSet(mode, S_IWGRP));
}
return AccessType.valueOf(isSet(mode, S_IWOTH));
}
@Override
public AccessType canGetAttributes(Subject subject,
FileAttributes attr,
Set<FileAttribute> attributes)
{
// posix always allowes to read attributes
return ACCESS_ALLOWED;
}
}