/** * Copyright (c) Istituto Nazionale di Fisica Nucleare, 2006-2014. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.italiangrid.voms.util; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.EnumSet; import org.italiangrid.voms.VOMSError; import org.italiangrid.voms.credential.FilePermissionError; /** * An helper class that does simple unix file permissions checks (until we get * proper support for this stuff in Java 7) * * @author Andrea Ceccanti * */ public class FilePermissionHelper { public static enum PosixFilePermission { USER_RO("400", "-r--------"), USER_RW("600", "-rw-------"), USER_ALL("700", "-rwx------"), ALL_PERMS("777", "-rwxrwxrwx"); private PosixFilePermission(String chmodForm, String statForm) { this.chmodForm = chmodForm; this.statForm = statForm; } private String statForm; private String chmodForm; public String statForm() { return statForm; } public String chmodForm() { return chmodForm; } } /** * Required file permissions for the private key file */ public static final EnumSet<PosixFilePermission> PRIVATE_KEY_PERMS = EnumSet .of(PosixFilePermission.USER_RO, PosixFilePermission.USER_RW); /** * String representation of private key required permissions. */ public static final String PRIVATE_KEY_PERMS_STR = PosixFilePermission.USER_RO .chmodForm() + ", " + PosixFilePermission.USER_RW.chmodForm(); /** * The command used to retrieve file permissions for a given file */ public static final String LS_CMD_TEMPLATE = "ls -al %s"; /** * The command used to set file permissions on a given file */ public static final String CHMOD_CMD_TEMPLATE = "chmod %s %s"; /** * Checks whether a proxy file has the right permissions * * @param proxyFile * the file to be checked * * @throws IOException * if an error occurs checking file attributes * @throws FilePermissionError * if permissions are not as expected */ public static void checkProxyPermissions(String proxyFile) throws IOException { matchesFilePermissions(proxyFile, PosixFilePermission.USER_RW); } /** * Checks whether a private key file has the 'right' permissions * * @param privateKeyFile * the file to be checked * @throws IOException * if an error occurs checking file attributes * @throws FilePermissionError * if the permissions are not correct */ public static void checkPrivateKeyPermissions(String privateKeyFile) throws IOException { for (PosixFilePermission p : PRIVATE_KEY_PERMS) { try { matchesFilePermissions(privateKeyFile, p); return; } catch (FilePermissionError e) { } } final String errorMessage = String.format( "Wrong file permissions on file %s. Required permissions are: %s ", privateKeyFile, PRIVATE_KEY_PERMS_STR); throw new FilePermissionError(errorMessage); } /** * Chekcs whether a pkcs12 file has the 'right' permissions * * @param pkcs12File * the file to be checked * @throws IOException * if an error occurs checking file attributes * @throws FilePermissionError * if the permissions are not correct */ public static void checkPKCS12Permissions(String pkcs12File) throws IOException { matchesFilePermissions(pkcs12File, PosixFilePermission.USER_RW); } /** * Checks that a given file has the appropriate unix permissions. This naive * implementation just fetches the output of ls -al on a given file and * matches the resulting string with the permissionString passed as argument. * * So the permissionString must be something like: * * <pre> * -rw------- * </pre> * * @param filename * the filename to be checked * @param p * the permission string that must be matched * @throws IOException * if an error occurs checking file attributes * @throws FilePermissionError * if file permissions are not as requested */ public static void matchesFilePermissions(String filename, PosixFilePermission p) throws IOException { filenameSanityChecks(filename); if (p == null) throw new NullPointerException("null permission passed as argument"); File f = new File(filename); // Don't get fooled by symlinks... String canonicalPath = f.getCanonicalPath(); String filePerms = getFilePermissions(canonicalPath); if (!filePerms.startsWith(p.statForm)) throw new FilePermissionError("Wrong file permissions on file " + filename + ". Required permissions are: " + p.chmodForm()); } private static void filenameSanityChecks(String filename) { if (filename == null) throw new NullPointerException("null filename passed as argument"); File f = new File(filename); if (!f.exists()) throw new VOMSError("File not found: " + filename); } private static String getFilePermissions(String filename) { String cmd = String.format(LS_CMD_TEMPLATE, filename); String permString; ProcessBuilder pb = new ProcessBuilder(cmd.split(" ")); try { Process p = pb.start(); int exitStatus = p.waitFor(); if (exitStatus != 0) throw new VOMSError("Cannot list properties for file '" + filename + "': error invoking the '" + cmd + "' os command!"); BufferedReader r = new BufferedReader(new InputStreamReader( p.getInputStream())); permString = r.readLine(); if (permString == null) throw new VOMSError("Cannot list properties for file '" + filename + "': the output of '" + cmd + "' is empty!"); return permString; } catch (IOException e) { throw new VOMSError("Cannot list properties for file '" + filename + "': " + e.getMessage(), e); } catch (InterruptedException e) { return null; } } public static void setProxyPermissions(String filename) { filenameSanityChecks(filename); setFilePermissions(filename, PosixFilePermission.USER_RW); } public static void setPKCS12Permissions(String filename) { filenameSanityChecks(filename); setFilePermissions(filename, PosixFilePermission.USER_RW); } public static void setPrivateKeyPermissions(String filename) { filenameSanityChecks(filename); setFilePermissions(filename, PosixFilePermission.USER_RO); } public static void setFilePermissions(String filename, PosixFilePermission perm) { String cmd = String.format(CHMOD_CMD_TEMPLATE, perm.chmodForm(), filename); ProcessBuilder pb = new ProcessBuilder(cmd.split(" ")); try { Process p = pb.start(); int exitStatus = p.waitFor(); if (exitStatus != 0) throw new VOMSError("Cannot change permissions on file '" + filename + "': error invoking the '" + cmd + "' os command!"); } catch (IOException e) { throw new VOMSError("Cannot list properties for file '" + filename + "': " + e.getMessage(), e); } catch (InterruptedException e) { throw new VOMSError("Interrupted while running os command!", e); } } }