package org.dcache.srm.handler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.net.URI; import org.dcache.srm.AbstractStorageElement; import org.dcache.srm.FileMetaData; import org.dcache.srm.SRM; import org.dcache.srm.SRMAuthorizationException; import org.dcache.srm.SRMException; import org.dcache.srm.SRMInternalErrorException; import org.dcache.srm.SRMInvalidPathException; import org.dcache.srm.SRMUser; import org.dcache.srm.v2_2.ArrayOfTGroupPermission; import org.dcache.srm.v2_2.ArrayOfTUserPermission; import org.dcache.srm.v2_2.SrmSetPermissionRequest; import org.dcache.srm.v2_2.SrmSetPermissionResponse; import org.dcache.srm.v2_2.TGroupPermission; import org.dcache.srm.v2_2.TPermissionMode; import org.dcache.srm.v2_2.TPermissionType; import org.dcache.srm.v2_2.TReturnStatus; import org.dcache.srm.v2_2.TStatusCode; import static com.google.common.base.Preconditions.checkNotNull; public class SrmSetPermission { private static final Logger LOGGER = LoggerFactory.getLogger(SrmSetPermission.class); private static final String ACL_NOT_SUPPORTED = "ACLs are not supported by the dCache SRM"; private final AbstractStorageElement storage; private final SrmSetPermissionRequest request; private final SRMUser user; private SrmSetPermissionResponse response; public SrmSetPermission(SRMUser user, SrmSetPermissionRequest request, AbstractStorageElement storage, SRM srm, String clientHost) { this.request = checkNotNull(request); this.user = checkNotNull(user); this.storage = checkNotNull(storage); } public SrmSetPermissionResponse getResponse() { if (response == null) { try { response = srmSetPermission(); } catch (SRMInternalErrorException e) { LOGGER.error(e.getMessage()); response = getFailedResponse(e.getMessage(), TStatusCode.SRM_INTERNAL_ERROR); } catch (SRMAuthorizationException e) { response = getFailedResponse(e.getMessage(), TStatusCode.SRM_AUTHORIZATION_FAILURE); } catch (SRMInvalidPathException e) { response = getFailedResponse(e.getMessage(), TStatusCode.SRM_INVALID_PATH); } catch (SRMException e) { response = getFailedResponse(e.getMessage()); } } return response; } private SrmSetPermissionResponse srmSetPermission() throws SRMException { URI surl = URI.create(request.getSURL().toString()); FileMetaData fmd = storage.getFileMetaData(user, surl, false); TPermissionType permissionType = request.getPermissionType(); if (permissionType == TPermissionType.REMOVE) { /* [ SRM 2.2, 3.1.2 ] * * h) If TPermissionType is REMOVE, then the TPermissionMode must be ignored. * * We interpret this requirement to apply to user and group ACLs only. Since * we don't support these, we don't support REMOVE. */ return getFailedResponse(ACL_NOT_SUPPORTED, TStatusCode.SRM_NOT_SUPPORTED); } TPermissionMode ownerMode = request.getOwnerPermission(); TPermissionMode otherMode = request.getOtherPermission(); TPermissionMode groupMode = null; ArrayOfTUserPermission userPermissions = request.getArrayOfUserPermissions(); if (userPermissions != null) { return getFailedResponse(ACL_NOT_SUPPORTED, TStatusCode.SRM_NOT_SUPPORTED); } ArrayOfTGroupPermission groupPermissions = request.getArrayOfGroupPermissions(); if (groupPermissions != null && groupPermissions.getGroupPermissionArray() != null) { switch (groupPermissions.getGroupPermissionArray().length) { case 0: break; case 1: TGroupPermission permission = groupPermissions.getGroupPermissionArray()[0]; String group = permission.getGroupID(); if (!group.equals("-") && !group.equals(fmd.group)) { /* The dash is a special dCache convention used by our own SRM client to * indicate that the POSIX group permissions should be updated. */ return getFailedResponse(ACL_NOT_SUPPORTED, TStatusCode.SRM_NOT_SUPPORTED); } groupMode = permission.getMode(); break; default: return getFailedResponse(ACL_NOT_SUPPORTED, TStatusCode.SRM_NOT_SUPPORTED); } } fmd.permMode = toNewPermissions(fmd.permMode, permissionType, ownerMode, groupMode, otherMode); storage.setFileMetaData(user, fmd); return new SrmSetPermissionResponse(new TReturnStatus(TStatusCode.SRM_SUCCESS, null)); } private static int toNewPermissions(int permissions, TPermissionType permissionType, TPermissionMode ownerPermission, TPermissionMode groupPermission, TPermissionMode otherPermission) { int iowner = (permissions >> 6) & 0x7; int igroup = (permissions >> 3) & 0x7; int iother = permissions & 0x7; int requestOwner = toMode(ownerPermission, iowner); int requestGroup = toMode(groupPermission, igroup); int requestOther = toMode(otherPermission, iother); if (permissionType == TPermissionType.CHANGE) { iowner = requestOwner; igroup = requestGroup; iother = requestOther; } else if (permissionType == TPermissionType.ADD) { iowner |= requestOwner; igroup |= requestGroup; iother |= requestOther; } return ((iowner << 6) | (igroup << 3)) | iother; } private static int toMode(TPermissionMode newPermissions, int existingMode) { /* [ SRM 2.2, 3.1.2 ] * * g) If TPermissionType is ADD or CHANGE, and TPermissionMode is null, then it * must be assumed that TPermissionMode is READ only. * * We interpret this requirement to apply to the user and group ACLs only. Since * we don't support those, we let an absent TPermissionMode imply that the * permission should not be changed. */ return (newPermissions == null) ? existingMode : PermissionMaskToTPermissionMode.permissionModetoMask(newPermissions); } public static final SrmSetPermissionResponse getFailedResponse(String error) { return getFailedResponse(error, TStatusCode.SRM_FAILURE); } public static final SrmSetPermissionResponse getFailedResponse(String error, TStatusCode statusCode) { SrmSetPermissionResponse response = new SrmSetPermissionResponse(); response.setReturnStatus(new TReturnStatus(statusCode, error)); return response; } }