/* * @(#)IxcPermission.java 1.7 06/10/10 * * Copyright 1990-2008 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * 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 * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package javax.microedition.xlet.ixc; import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.List; import java.util.Vector; import java.security.Permission; import java.security.PermissionCollection; public final class IxcPermission extends Permission { /** * Bind action. */ private final static int BIND = 0x1; /** * Lookup action. */ private final static int LOOKUP = 0x2; /** * All actions (bind,lookup) */ private final static int ALL = BIND|LOOKUP; /** * No actions. */ private final static int NONE = 0x0; // the actions mask private transient int mask; // static Strings used by init(int mask) private static final char WILD_CHAR = '*'; // canonicalized dir path. In the case of // directories, it is the name "/blah/*" without // the last character (the "*" or "-"). private transient String cpath; /** * the actions string. * * @serial */ private String actions; // Left null as long as possible, then // created and re-used in the getAction function. // does path include a wildcard? private transient boolean wildcard; /** public String toString() { StringBuffer sb = new StringBuffer(); sb.append("***\n"); sb.append("cpath = "+cpath+"\n"); sb.append("mask = "+mask+"\n"); sb.append("actions = "+getActions()+"\n"); sb.append("wildcard = "+wildcard+"\n"); sb.append("***\n"); return sb.toString(); } **/ /* * Initialize a IxcPermission object. Common to all constructors. * Also called during de-serialization. * * @param mask the actions mask to use. */ private void init(int mask) { if ((mask & ALL) != mask) throw new IllegalArgumentException("invalid actions mask"); if (mask == NONE) throw new IllegalArgumentException("invalid actions mask"); if ((cpath = getName()) == null) throw new NullPointerException("name can't be null"); this.mask = mask; int len = cpath.length(); char last = ((len > 0) ? cpath.charAt(len - 1) : 0); if (last == WILD_CHAR && (len == 1 || cpath.charAt(len - 2) == '/')) { //6254827 wildcard = true; cpath = cpath.substring(0, --len); } } /** * Converts an actions String to an actions mask. * * @param action the action string. * @return the actions mask. */ private static int getMask(String actions) { int mask = NONE; if (actions == null) { return mask; } char[] a = actions.toCharArray(); int i = a.length - 1; if (i < 0) return mask; while (i != -1) { char c; // skip whitespace while ((i!=-1) && ((c = a[i]) == ' ' || c == '\r' || c == '\n' || c == '\f' || c == '\t')) i--; // check for the known strings int matchlen; if (i >= 3 && (a[i-3] == 'b' || a[i-3] == 'B') && (a[i-2] == 'i' || a[i-2] == 'I') && (a[i-1] == 'n' || a[i-1] == 'N') && (a[i] == 'd' || a[i] == 'D')) { matchlen = 4; mask |= BIND; } else if (i >= 5 && (a[i-5] == 'l' || a[i-5] == 'L') && (a[i-4] == 'o' || a[i-4] == 'O') && (a[i-3] == 'o' || a[i-3] == 'O') && (a[i-2] == 'k' || a[i-2] == 'K') && (a[i-1] == 'u' || a[i-1] == 'U') && (a[i] == 'p' || a[i] == 'P')) { matchlen = 6; mask |= LOOKUP; } else { // parse error throw new IllegalArgumentException( "invalid permission: " + actions); } // make sure we didn't just match the tail of a word // like "ackbarfaccept". Also, skip to the comma. boolean seencomma = false; while (i >= matchlen && !seencomma) { switch(a[i-matchlen]) { case ',': seencomma = true; /*FALLTHROUGH*/ case ' ': case '\r': case '\n': case '\f': case '\t': break; default: throw new IllegalArgumentException( "invalid permission: " + actions); } i--; } // point i at the location of the comma minus one (or -1). i -= matchlen; } return mask; } /** * Return the current action mask. Used by the IxcPermissionCollection. * * @return the actions mask. */ int getMask() { return mask; } public IxcPermission(String name, String actions) { super(name); init(getMask(actions)); } // package private for use by the IxcPermissionCollection add method IxcPermission(String path, int mask) { super(path); init(mask); } public boolean implies(Permission p) { if (!(p instanceof IxcPermission)) return false; IxcPermission that = (IxcPermission) p; // we get the effective mask. i.e., the "and" of this and that. // They must be equal to that.mask for implies to return true. return ((this.mask & that.mask) == that.mask) && impliesIgnoreMask(that); } /** * Checks if the Permission's actions are a proper subset of the * this object's actions. Returns the effective mask iff the * this IxcPermission's path also implies that IxcPermission's path. * * @param that the IxcPermission to check against. * @param exact return immediatly if the masks are not equal * @return the effective mask */ boolean impliesIgnoreMask(IxcPermission that) { if (this.wildcard) { if (that.wildcard) { // if the permission passed in is a directory // specification, make sure that a non-recursive // permission (i.e., this object) can't imply a recursive // permission. if (this.cpath.equals(that.cpath)) return true; else if (this.cpath.length() == 0) return true; else // A/B/* implies A/B/C/* // A/*/D is not a valid wildcard return (that.cpath.indexOf(this.cpath)==0 && that.cpath.length() > this.cpath.length()); } else { int last = that.cpath.lastIndexOf('/'); //6254827 if (last == -1) { // Check for the wildcard instead of returning // false blindly return (this.cpath.length() == 0); } else { // this.cpath.equals(that.cpath.substring(0, last+1)); // Use regionMatches to avoid creating new string // A/B/* implies A/B/C return (this.cpath.length() <= (last + 1)) && this.cpath.regionMatches(0, that.cpath, 0, this.cpath.length()); //this.cpath.regionMatches(0, that.cpath, 0, last+1); } } } else { return (this.cpath.equals(that.cpath)); } } public boolean equals(Object obj) { if (obj == this) return true; if (!(obj instanceof IxcPermission)) return false; IxcPermission that = (IxcPermission) obj; return ((this.mask == that.mask) && this.cpath.equals(that.cpath) && (this.wildcard == that.wildcard)); } public int hashCode() { return this.cpath.hashCode(); } private static String getActions(int mask) { StringBuffer sb = new StringBuffer(); boolean comma = false; if ((mask & BIND) == BIND) { comma = true; sb.append("bind"); } if ((mask & LOOKUP) == LOOKUP) { if (comma) sb.append(','); else comma = true; sb.append("lookup"); } return sb.toString(); } public String getActions() { if (actions == null) actions = getActions(this.mask); return actions; } public java.security.PermissionCollection newPermissionCollection() { return new IxcPermissionCollection(); } } final class IxcPermissionCollection extends PermissionCollection { // Not serialized; see serialization section at end of class private transient List perms; /** * Create an empty IxcPermissions object. */ public IxcPermissionCollection() { perms = new ArrayList(); } /** * Adds a permission to the IxcPermissions. The key for the hash is * permission.path. * * @param permission the Permission object to add. * @exception IllegalArgumentException - if the permission is not a * IxcPermission * @exception SecurityException - if this IxcPermissionCollection object * has been marked readonly */ public void add(Permission permission) { if (! (permission instanceof IxcPermission)) throw new IllegalArgumentException("invalid permission: "+ permission); if (isReadOnly()) throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection"); // No need to synchronize because all adds are done sequentially // before any implies() calls perms.add(permission); } /** * Check and see if this set of permissions implies the permissions * expressed in "permission". * * @param p the Permission object to compare * @return true if "permission" is a proper subset of a permission in * the set, false if not. */ public boolean implies(Permission permission) { if (!(permission instanceof IxcPermission)) return false; IxcPermission fp = (IxcPermission) permission; int desired = fp.getMask(); int effective = 0; int needed = desired; int len = perms.size(); for (int i = 0; i < len; i++) { IxcPermission x = (IxcPermission) perms.get(i); if (((needed & x.getMask()) != 0) && x.impliesIgnoreMask(fp)) { effective |= x.getMask(); if ((effective & desired) == desired) return true; needed = (desired ^ effective); } } return false; } /** * Returns an enumeration of all the IxcPermission objects in the * container. * * @return an enumeration of all the IxcPermission objects. */ public Enumeration elements() { // Convert Iterator into Enumeration return Collections.enumeration(perms); } }