Package org.exist.security

Source Code of org.exist.security.AbstractUnixStylePermission

/*
*  eXist Open Source Native XML Database
*  Copyright (C) 2001-2013 The eXist-db Project
*  http://exist-db.org
*
*  This program is free software; you can redistribute it and/or
*  modify it under the terms of the GNU Lesser General Public License
*  as published by the Free Software Foundation; either version 2
*  of the License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Lesser General Public License for more details.
*
*  You should have received a copy of the GNU Lesser General Public License
*  along with this program; if not, write to the Free Software
*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*  $Id: UnixStylePermission.java 14571 2011-05-29 12:34:48Z deliriumsky $
*/
package org.exist.security;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.log4j.Logger;
import org.exist.util.SyntaxException;

/**
* All code in this class must be side-effect free
* and not carry state, thus ensuring that thus class
* can be used in a local or remote scenario
*
* @author Adam Retter <adam@exist-db.org>
*/
public abstract class AbstractUnixStylePermission implements Permission {

    private final static Logger LOG = Logger.getLogger(AbstractUnixStylePermission.class);

    /**
     * The symbolic mode is described by the following grammar:
     *
     * mode         ::= clause [, clause ...]
     * clause       ::= [who ...] [action ...] action
     * action       ::= op [perm ...]
     * who          ::= a | u | g | o
     * op           ::= + | - | =
     * perm         ::= r | s | t | w | x
     */
    private void setUnixSymbolicMode(final String symbolicMode)
            throws SyntaxException, PermissionDeniedException {

        //TODO expand perm to full UNIX chmod i.e. perm ::= r | s | t | w | x | X | u | g | o

        final String clauses[] = symbolicMode.split(",");
        for(final String clause : clauses) {
            final String whoPerm[] = clause.split("[+\\-=]");

            int perm = 0;
            boolean uidgid = false;
            boolean sticky = false;
            //process the op first
            for(final char c : whoPerm[1].toCharArray()) {
                switch(c) {
                    case READ_CHAR:
                        perm |= READ;
                        break;

                    case WRITE_CHAR:
                        perm |= WRITE;
                        break;

                    case EXECUTE_CHAR:
                        perm |= EXECUTE;
                        break;

                    case SETUID_CHAR:
                        uidgid = true;
                        break;

                    case STICKY_CHAR:
                        sticky = true;
                        break;

                    default:
                        throw new SyntaxException("Unrecognised mode char '" + c + "'");
                }
            }

           
            final char whoose[];
            if(whoPerm[0].length() > 0) {
                whoose = whoPerm[0].toCharArray();
            } else {
                whoose = new char[]{ ALL_CHAR };
            }
           
            for(final char c: whoose) {
                switch(c) {
                    case ALL_CHAR:
                        final int newMode = (perm << 6) | (perm << 3) | perm | (sticky ? (STICKY << 9) : 0) | (uidgid ? ((SET_UID | SET_GID) << 9) : 0);
                        if(clause.indexOf("+") > -1) {
                            setMode(getMode() | newMode);
                        } else if(clause.indexOf("-") > -1) {
                            setMode(getMode() & ~newMode);
                        } else if(clause.indexOf("=") > -1) {
                            setMode(newMode);
                        }
                        break;

                    case USER_CHAR:
                        if(clause.indexOf("+") > -1) {
                            setOwnerMode(getOwnerMode() | perm);
                            if(uidgid) {
                                setSetUid(true);
                            }
                        } else if(clause.indexOf("-") > -1) {
                            setOwnerMode(getOwnerMode() & ~perm);
                            if(uidgid) {
                                setSetUid(false);
                            }
                        } else if(clause.indexOf("=") > -1) {
                            setOwnerMode(perm);
                            if(uidgid) {
                                setSetUid(true);
                            }
                        }
                        break;

                    case GROUP_CHAR:
                        if(clause.indexOf("+") > -1) {
                            setGroupMode(getGroupMode() | perm);
                            if(uidgid) {
                                setSetGid(true);
                            }
                        } else if(clause.indexOf("-") > -1) {
                            setGroupMode(getGroupMode() & ~perm);
                            if(uidgid) {
                                setSetGid(false);
                            }
                        } else if(clause.indexOf("=") > -1) {
                            setGroupMode(perm);
                            if(uidgid) {
                                setSetGid(true);
                            }
                        }
                        break;

                    case OTHER_CHAR:
                        if(clause.indexOf("+") > -1) {
                            setOtherMode(getOtherMode() | perm);
                            if(sticky) {
                                setSticky(true);
                            }
                        } else if(clause.indexOf("-") > -1) {
                            setOtherMode(getOtherMode() & ~perm);
                            if(sticky) {
                                setSticky(false);
                            }
                        } else if(clause.indexOf("=") > -1) {
                            setOtherMode(perm);
                            if(sticky) {
                                setSticky(true);
                            }
                        }
                        break;

                    default:
                        throw new SyntaxException("Unrecognised mode char '" + c + "'");
                }
            }

            perm = 0;
            uidgid = false;
            sticky = false;
        }
    }

    /**
     * Set mode using a string. The string has the
     * following syntax:
     *
     * [user|group|other]=[+|-][read|write|execute]
     *
     * For example, to set read and write mode for the group, but
     * not for others:
     *
     * group=+read,+write,other=-read,-write
     *
     * The new settings are or'ed with the existing settings.
     *
     *@param  existSymbolicMode                  The new mode
     *@exception  SyntaxException  Description of the Exception
     *
     * @deprecated setUnixSymbolicMode should be used instead
     */
    @Deprecated
    private void setExistSymbolicMode(final String existSymbolicMode)
            throws SyntaxException, PermissionDeniedException {

        LOG.warn("Permission modes should not be set using this format '" + existSymbolicMode + "', consider using the UNIX symbolic mode instead");

        int shift = 0;
        int mode = getMode();
        for(final String s : existSymbolicMode.toLowerCase().split("=|,")){
            if(s.equalsIgnoreCase(USER_STRING)) {
                shift = 6;
            } else if(s.equalsIgnoreCase(GROUP_STRING)) {
                shift = 3;
            } else if(s.equalsIgnoreCase(OTHER_STRING)) {
                shift = 0;
            } else {
                int perm = 0;

                if(s.endsWith(READ_STRING.toLowerCase())) {
                    perm = READ;
                } else if(s.endsWith(WRITE_STRING.toLowerCase())) {
                    perm = WRITE;
                } else if(s.endsWith(EXECUTE_STRING.toLowerCase())) {
                    perm = EXECUTE;
                } else {
                    throw new SyntaxException("Unrecognised mode char '" + s + "'");
                }

                if(s.startsWith("+")) {
                    mode |= (perm << shift);
                } else if(s.startsWith("-")) {
                    mode &= (~(perm << shift));
                } else {
                    throw new SyntaxException("Unrecognised mode char '" + s + "'");
                }
            }
        }
        setMode(mode);
    }

    /**
     * Simple symbolic mode is [rwxs-]{3}[rwxs-]{3}[rwxt-]{3}
     */
    private void setSimpleSymbolicMode(final String simpleSymbolicMode)
            throws SyntaxException, PermissionDeniedException {
        setMode(simpleSymbolicModeToInt(simpleSymbolicMode));
    }

    private final static Pattern unixSymbolicModePattern = Pattern.compile("((?:[augo]*(?:[+\\-=](?:[" + READ_CHAR + SETUID_CHAR + STICKY_CHAR + WRITE_CHAR + EXECUTE_CHAR +"])+)+),?)+");
    private final static Matcher unixSymbolicModeMatcher = unixSymbolicModePattern.matcher("");

    private final static Pattern existSymbolicModePattern = Pattern.compile("(?:(?:" + USER_STRING + "|" + GROUP_STRING + "|" + OTHER_STRING + ")=(?:[+-](?:" + READ_STRING + "|" + WRITE_STRING + "|" + EXECUTE_STRING + "),?)+)+");
    private final static Matcher existSymbolicModeMatcher = existSymbolicModePattern.matcher("");

    private final static Pattern simpleSymbolicModePattern = Pattern.compile("(?:(?:" + READ_CHAR + "|" + UNSET_CHAR + ")(?:" + WRITE_CHAR + "|" + UNSET_CHAR + ")(?:[" + EXECUTE_CHAR + SETUID_CHAR + SETUID_CHAR_NO_EXEC + "]|" + UNSET_CHAR + ")){2}(?:" + READ_CHAR + "|" + UNSET_CHAR + ")(?:" + WRITE_CHAR + "|" + UNSET_CHAR + ")(?:[" + EXECUTE_CHAR + STICKY_CHAR + "]|" + UNSET_CHAR + ")");
    private final static Matcher simpleSymbolicModeMatcher = simpleSymbolicModePattern.matcher("");

    /**
     * Note: we don't need @PermissionRequired(user = IS_DBA | IS_OWNER) here
     * because all of these methods delegate to the subclass implementation.
     *
     * @param modeStr The String representing a mode to set
     *
     * @throws org.exist.util.SyntaxException If the string syntax for the mode
     * is not recognised. The following syntaxes are supported. Simple symbolic,
     * Unix symbolic, eXist symbolic.
     *
     * @throws org.exist.security.PermissionDeniedException If you do not have
     * permission to set the mode
     */
    @Override
    public final void setMode(final String modeStr)
            throws SyntaxException, PermissionDeniedException {
        simpleSymbolicModeMatcher.reset(modeStr);

        if(simpleSymbolicModeMatcher.matches()) {
            setSimpleSymbolicMode(modeStr);
        } else {
            unixSymbolicModeMatcher.reset(modeStr);
            if(unixSymbolicModeMatcher.matches()){
                setUnixSymbolicMode(modeStr);
            } else {
                existSymbolicModeMatcher.reset(modeStr);
                if(existSymbolicModeMatcher.matches()) {
                    setExistSymbolicMode(modeStr);
                } else {
                    throw new SyntaxException("Unknown mode String: " + modeStr);
                }
            }
        }
    }
   
    public static int simpleSymbolicModeToInt(final String simpleModeStr) throws SyntaxException {
        int mode = 0;

        final char modeArray[] = simpleModeStr.toCharArray();
        for(int i = 0; i < modeArray.length; i++) {

            final char c = modeArray[i];
            final int shift = (i < 3 ? 6 : (i < 6 ? 3 : 0));

            switch(c) {
                case READ_CHAR:
                    mode |= (READ << shift);
                    break;
                case WRITE_CHAR:
                    mode |= (WRITE << shift);
                    break;
                case EXECUTE_CHAR:
                    mode |= (EXECUTE << shift);
                    break;
                case SETUID_CHAR_NO_EXEC:
                case SETUID_CHAR:
                    if(i < 3) {
                        mode |= (SET_UID << 9);
                    } else {
                        mode |= (SET_GID << 9);
                    }
                    if(c == SETUID_CHAR) {
                        mode |= (EXECUTE << shift);
                    }
                    break;
                case STICKY:
                    mode |= (STICKY << 9);
                    break;

                case UNSET_CHAR:
                    break;

                default:
                    throw new SyntaxException("Unrecognised mode char '" + c + "'");
            }
        }
       
        return mode;
    }
   
    public static String modeToSimpleSymbolicMode(final int mode) {
        final char ch[] = new char[] {
            (mode & (READ << 6)) == 0 ? UNSET_CHAR : READ_CHAR,
            (mode & (WRITE << 6)) == 0 ? UNSET_CHAR : WRITE_CHAR,
            (mode & (EXECUTE << 6)) == 0 ? UNSET_CHAR : EXECUTE_CHAR,
           
            (mode & (READ << 3)) == 0 ? UNSET_CHAR : READ_CHAR,
            (mode & (WRITE << 3)) == 0 ? UNSET_CHAR : WRITE_CHAR,
            (mode & (EXECUTE << 3)) == 0 ? UNSET_CHAR : EXECUTE_CHAR,

            (mode & READ) == 0 ? UNSET_CHAR : READ_CHAR,
            (mode & WRITE) == 0 ? UNSET_CHAR : WRITE_CHAR,
            (mode & EXECUTE) == 0 ? UNSET_CHAR : EXECUTE_CHAR
        };
        return String.valueOf(ch);
    }
   
    /**
     * Utility function for external use
     *
     * @param types Types to convert to a string representation
     * @return The string representation of the types
     */
    public static String typesToString(final int types) {
        final StringBuilder builder = new StringBuilder();
       
        if((types >> 8) > 0) {
            if(((types >> 8) & READ) == READ) {
                builder.append(READ_CHAR);
            } else {
                builder.append(UNSET_CHAR);
            }

            if(((types >> 8) & WRITE) == WRITE) {
                builder.append(WRITE_CHAR);
            } else {
                builder.append(UNSET_CHAR);
            }

            if(((types >> 8) & EXECUTE) == EXECUTE) {
                builder.append(EXECUTE_CHAR);
            } else {
                builder.append(UNSET_CHAR);
            }
        }
       
        if((types >> 4) > 0) {
            if(((types >> 4) & READ) == READ) {
                builder.append(READ_CHAR);
            } else {
                builder.append(UNSET_CHAR);
            }

            if(((types >> 4) & WRITE) == WRITE) {
                builder.append(WRITE_CHAR);
            } else {
                builder.append(UNSET_CHAR);
            }

            if(((types >> 4) & EXECUTE) == EXECUTE) {
                builder.append(EXECUTE_CHAR);
            } else {
                builder.append(UNSET_CHAR);
            }
        }
       
        if((types & READ) == READ) {
            builder.append(READ_CHAR);
        } else {
            builder.append(UNSET_CHAR);
        }
       
        if((types & WRITE) == WRITE) {
            builder.append(WRITE_CHAR);
        } else {
            builder.append(UNSET_CHAR);
        }
       
        if((types & EXECUTE) == EXECUTE) {
            builder.append(EXECUTE_CHAR);
        } else {
            builder.append(UNSET_CHAR);
        }
       
        return builder.toString();
    }
}
TOP

Related Classes of org.exist.security.AbstractUnixStylePermission

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.