Home » openjdk-7 » java » util » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2003, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package java.util;
   27   
   28   import java.io.Serializable;
   29   import java.io.IOException;
   30   import java.security;
   31   import java.util.Map;
   32   import java.util.HashMap;
   33   import java.util.Enumeration;
   34   import java.util.Hashtable;
   35   import java.util.Collections;
   36   import java.io.ObjectStreamField;
   37   import java.io.ObjectOutputStream;
   38   import java.io.ObjectInputStream;
   39   import java.io.IOException;
   40   import sun.security.util.SecurityConstants;
   41   
   42   /**
   43    * This class is for property permissions.
   44    *
   45    * <P>
   46    * The name is the name of the property ("java.home",
   47    * "os.name", etc). The naming
   48    * convention follows the  hierarchical property naming convention.
   49    * Also, an asterisk
   50    * may appear at the end of the name, following a ".", or by itself, to
   51    * signify a wildcard match. For example: "java.*" or "*" is valid,
   52    * "*java" or "a*b" is not valid.
   53    * <P>
   54    * <P>
   55    * The actions to be granted are passed to the constructor in a string containing
   56    * a list of one or more comma-separated keywords. The possible keywords are
   57    * "read" and "write". Their meaning is defined as follows:
   58    * <P>
   59    * <DL>
   60    *    <DT> read
   61    *    <DD> read permission. Allows <code>System.getProperty</code> to
   62    *         be called.
   63    *    <DT> write
   64    *    <DD> write permission. Allows <code>System.setProperty</code> to
   65    *         be called.
   66    * </DL>
   67    * <P>
   68    * The actions string is converted to lowercase before processing.
   69    * <P>
   70    * Care should be taken before granting code permission to access
   71    * certain system properties.  For example, granting permission to
   72    * access the "java.home" system property gives potentially malevolent
   73    * code sensitive information about the system environment (the Java
   74    * installation directory).  Also, granting permission to access
   75    * the "user.name" and "user.home" system properties gives potentially
   76    * malevolent code sensitive information about the user environment
   77    * (the user's account name and home directory).
   78    *
   79    * @see java.security.BasicPermission
   80    * @see java.security.Permission
   81    * @see java.security.Permissions
   82    * @see java.security.PermissionCollection
   83    * @see java.lang.SecurityManager
   84    *
   85    *
   86    * @author Roland Schemers
   87    * @since 1.2
   88    *
   89    * @serial exclude
   90    */
   91   
   92   public final class PropertyPermission extends BasicPermission {
   93   
   94       /**
   95        * Read action.
   96        */
   97       private final static int READ    = 0x1;
   98   
   99       /**
  100        * Write action.
  101        */
  102       private final static int WRITE   = 0x2;
  103       /**
  104        * All actions (read,write);
  105        */
  106       private final static int ALL     = READ|WRITE;
  107       /**
  108        * No actions.
  109        */
  110       private final static int NONE    = 0x0;
  111   
  112       /**
  113        * The actions mask.
  114        *
  115        */
  116       private transient int mask;
  117   
  118       /**
  119        * The actions string.
  120        *
  121        * @serial
  122        */
  123       private String actions; // Left null as long as possible, then
  124                               // created and re-used in the getAction function.
  125   
  126       /**
  127        * initialize a PropertyPermission object. Common to all constructors.
  128        * Also called during de-serialization.
  129        *
  130        * @param mask the actions mask to use.
  131        *
  132        */
  133   
  134       private void init(int mask)
  135       {
  136   
  137           if ((mask & ALL) != mask)
  138                   throw new IllegalArgumentException("invalid actions mask");
  139   
  140           if (mask == NONE)
  141                   throw new IllegalArgumentException("invalid actions mask");
  142   
  143           if (getName() == null)
  144                   throw new NullPointerException("name can't be null");
  145   
  146           this.mask = mask;
  147       }
  148   
  149       /**
  150        * Creates a new PropertyPermission object with the specified name.
  151        * The name is the name of the system property, and
  152        * <i>actions</i> contains a comma-separated list of the
  153        * desired actions granted on the property. Possible actions are
  154        * "read" and "write".
  155        *
  156        * @param name the name of the PropertyPermission.
  157        * @param actions the actions string.
  158        *
  159        * @throws NullPointerException if <code>name</code> is <code>null</code>.
  160        * @throws IllegalArgumentException if <code>name</code> is empty or if
  161        * <code>actions</code> is invalid.
  162        */
  163   
  164       public PropertyPermission(String name, String actions)
  165       {
  166           super(name,actions);
  167           init(getMask(actions));
  168       }
  169   
  170       /**
  171        * Checks if this PropertyPermission object "implies" the specified
  172        * permission.
  173        * <P>
  174        * More specifically, this method returns true if:<p>
  175        * <ul>
  176        * <li> <i>p</i> is an instanceof PropertyPermission,<p>
  177        * <li> <i>p</i>'s actions are a subset of this
  178        * object's actions, and <p>
  179        * <li> <i>p</i>'s name is implied by this object's
  180        *      name. For example, "java.*" implies "java.home".
  181        * </ul>
  182        * @param p the permission to check against.
  183        *
  184        * @return true if the specified permission is implied by this object,
  185        * false if not.
  186        */
  187       public boolean implies(Permission p) {
  188           if (!(p instanceof PropertyPermission))
  189               return false;
  190   
  191           PropertyPermission that = (PropertyPermission) p;
  192   
  193           // we get the effective mask. i.e., the "and" of this and that.
  194           // They must be equal to that.mask for implies to return true.
  195   
  196           return ((this.mask & that.mask) == that.mask) && super.implies(that);
  197       }
  198   
  199   
  200       /**
  201        * Checks two PropertyPermission objects for equality. Checks that <i>obj</i> is
  202        * a PropertyPermission, and has the same name and actions as this object.
  203        * <P>
  204        * @param obj the object we are testing for equality with this object.
  205        * @return true if obj is a PropertyPermission, and has the same name and
  206        * actions as this PropertyPermission object.
  207        */
  208       public boolean equals(Object obj) {
  209           if (obj == this)
  210               return true;
  211   
  212           if (! (obj instanceof PropertyPermission))
  213               return false;
  214   
  215           PropertyPermission that = (PropertyPermission) obj;
  216   
  217           return (this.mask == that.mask) &&
  218               (this.getName().equals(that.getName()));
  219       }
  220   
  221       /**
  222        * Returns the hash code value for this object.
  223        * The hash code used is the hash code of this permissions name, that is,
  224        * <code>getName().hashCode()</code>, where <code>getName</code> is
  225        * from the Permission superclass.
  226        *
  227        * @return a hash code value for this object.
  228        */
  229   
  230       public int hashCode() {
  231           return this.getName().hashCode();
  232       }
  233   
  234   
  235       /**
  236        * Converts an actions String to an actions mask.
  237        *
  238        * @param action the action string.
  239        * @return the actions mask.
  240        */
  241       private static int getMask(String actions) {
  242   
  243           int mask = NONE;
  244   
  245           if (actions == null) {
  246               return mask;
  247           }
  248   
  249           // Check against use of constants (used heavily within the JDK)
  250           if (actions == SecurityConstants.PROPERTY_READ_ACTION) {
  251               return READ;
  252           } if (actions == SecurityConstants.PROPERTY_WRITE_ACTION) {
  253               return WRITE;
  254           } else if (actions == SecurityConstants.PROPERTY_RW_ACTION) {
  255               return READ|WRITE;
  256           }
  257   
  258           char[] a = actions.toCharArray();
  259   
  260           int i = a.length - 1;
  261           if (i < 0)
  262               return mask;
  263   
  264           while (i != -1) {
  265               char c;
  266   
  267               // skip whitespace
  268               while ((i!=-1) && ((c = a[i]) == ' ' ||
  269                                  c == '\r' ||
  270                                  c == '\n' ||
  271                                  c == '\f' ||
  272                                  c == '\t'))
  273                   i--;
  274   
  275               // check for the known strings
  276               int matchlen;
  277   
  278               if (i >= 3 && (a[i-3] == 'r' || a[i-3] == 'R') &&
  279                             (a[i-2] == 'e' || a[i-2] == 'E') &&
  280                             (a[i-1] == 'a' || a[i-1] == 'A') &&
  281                             (a[i] == 'd' || a[i] == 'D'))
  282               {
  283                   matchlen = 4;
  284                   mask |= READ;
  285   
  286               } else if (i >= 4 && (a[i-4] == 'w' || a[i-4] == 'W') &&
  287                                    (a[i-3] == 'r' || a[i-3] == 'R') &&
  288                                    (a[i-2] == 'i' || a[i-2] == 'I') &&
  289                                    (a[i-1] == 't' || a[i-1] == 'T') &&
  290                                    (a[i] == 'e' || a[i] == 'E'))
  291               {
  292                   matchlen = 5;
  293                   mask |= WRITE;
  294   
  295               } else {
  296                   // parse error
  297                   throw new IllegalArgumentException(
  298                           "invalid permission: " + actions);
  299               }
  300   
  301               // make sure we didn't just match the tail of a word
  302               // like "ackbarfaccept".  Also, skip to the comma.
  303               boolean seencomma = false;
  304               while (i >= matchlen && !seencomma) {
  305                   switch(a[i-matchlen]) {
  306                   case ',':
  307                       seencomma = true;
  308                       /*FALLTHROUGH*/
  309                   case ' ': case '\r': case '\n':
  310                   case '\f': case '\t':
  311                       break;
  312                   default:
  313                       throw new IllegalArgumentException(
  314                               "invalid permission: " + actions);
  315                   }
  316                   i--;
  317               }
  318   
  319               // point i at the location of the comma minus one (or -1).
  320               i -= matchlen;
  321           }
  322   
  323           return mask;
  324       }
  325   
  326   
  327       /**
  328        * Return the canonical string representation of the actions.
  329        * Always returns present actions in the following order:
  330        * read, write.
  331        *
  332        * @return the canonical string representation of the actions.
  333        */
  334       static String getActions(int mask)
  335       {
  336           StringBuilder sb = new StringBuilder();
  337           boolean comma = false;
  338   
  339           if ((mask & READ) == READ) {
  340               comma = true;
  341               sb.append("read");
  342           }
  343   
  344           if ((mask & WRITE) == WRITE) {
  345               if (comma) sb.append(',');
  346               else comma = true;
  347               sb.append("write");
  348           }
  349           return sb.toString();
  350       }
  351   
  352       /**
  353        * Returns the "canonical string representation" of the actions.
  354        * That is, this method always returns present actions in the following order:
  355        * read, write. For example, if this PropertyPermission object
  356        * allows both write and read actions, a call to <code>getActions</code>
  357        * will return the string "read,write".
  358        *
  359        * @return the canonical string representation of the actions.
  360        */
  361       public String getActions()
  362       {
  363           if (actions == null)
  364               actions = getActions(this.mask);
  365   
  366           return actions;
  367       }
  368   
  369       /**
  370        * Return the current action mask.
  371        * Used by the PropertyPermissionCollection
  372        *
  373        * @return the actions mask.
  374        */
  375   
  376       int getMask() {
  377           return mask;
  378       }
  379   
  380       /**
  381        * Returns a new PermissionCollection object for storing
  382        * PropertyPermission objects.
  383        * <p>
  384        *
  385        * @return a new PermissionCollection object suitable for storing
  386        * PropertyPermissions.
  387        */
  388   
  389       public PermissionCollection newPermissionCollection() {
  390           return new PropertyPermissionCollection();
  391       }
  392   
  393   
  394       private static final long serialVersionUID = 885438825399942851L;
  395   
  396       /**
  397        * WriteObject is called to save the state of the PropertyPermission
  398        * to a stream. The actions are serialized, and the superclass
  399        * takes care of the name.
  400        */
  401       private synchronized void writeObject(java.io.ObjectOutputStream s)
  402           throws IOException
  403       {
  404           // Write out the actions. The superclass takes care of the name
  405           // call getActions to make sure actions field is initialized
  406           if (actions == null)
  407               getActions();
  408           s.defaultWriteObject();
  409       }
  410   
  411       /**
  412        * readObject is called to restore the state of the PropertyPermission from
  413        * a stream.
  414        */
  415       private synchronized void readObject(java.io.ObjectInputStream s)
  416            throws IOException, ClassNotFoundException
  417       {
  418           // Read in the action, then initialize the rest
  419           s.defaultReadObject();
  420           init(getMask(actions));
  421       }
  422   }
  423   
  424   /**
  425    * A PropertyPermissionCollection stores a set of PropertyPermission
  426    * permissions.
  427    *
  428    * @see java.security.Permission
  429    * @see java.security.Permissions
  430    * @see java.security.PermissionCollection
  431    *
  432    *
  433    * @author Roland Schemers
  434    *
  435    * @serial include
  436    */
  437   final class PropertyPermissionCollection extends PermissionCollection
  438   implements Serializable
  439   {
  440   
  441       /**
  442        * Key is property name; value is PropertyPermission.
  443        * Not serialized; see serialization section at end of class.
  444        */
  445       private transient Map perms;
  446   
  447       /**
  448        * Boolean saying if "*" is in the collection.
  449        *
  450        * @see #serialPersistentFields
  451        */
  452       // No sync access; OK for this to be stale.
  453       private boolean all_allowed;
  454   
  455       /**
  456        * Create an empty PropertyPermissions object.
  457        *
  458        */
  459   
  460       public PropertyPermissionCollection() {
  461           perms = new HashMap(32);     // Capacity for default policy
  462           all_allowed = false;
  463       }
  464   
  465       /**
  466        * Adds a permission to the PropertyPermissions. The key for the hash is
  467        * the name.
  468        *
  469        * @param permission the Permission object to add.
  470        *
  471        * @exception IllegalArgumentException - if the permission is not a
  472        *                                       PropertyPermission
  473        *
  474        * @exception SecurityException - if this PropertyPermissionCollection
  475        *                                object has been marked readonly
  476        */
  477   
  478       public void add(Permission permission)
  479       {
  480           if (! (permission instanceof PropertyPermission))
  481               throw new IllegalArgumentException("invalid permission: "+
  482                                                  permission);
  483           if (isReadOnly())
  484               throw new SecurityException(
  485                   "attempt to add a Permission to a readonly PermissionCollection");
  486   
  487           PropertyPermission pp = (PropertyPermission) permission;
  488           String propName = pp.getName();
  489   
  490           synchronized (this) {
  491               PropertyPermission existing = (PropertyPermission) perms.get(propName);
  492   
  493               if (existing != null) {
  494                   int oldMask = existing.getMask();
  495                   int newMask = pp.getMask();
  496                   if (oldMask != newMask) {
  497                       int effective = oldMask | newMask;
  498                       String actions = PropertyPermission.getActions(effective);
  499                       perms.put(propName, new PropertyPermission(propName, actions));
  500                   }
  501               } else {
  502                   perms.put(propName, permission);
  503               }
  504           }
  505   
  506           if (!all_allowed) {
  507               if (propName.equals("*"))
  508                   all_allowed = true;
  509           }
  510       }
  511   
  512       /**
  513        * Check and see if this set of permissions implies the permissions
  514        * expressed in "permission".
  515        *
  516        * @param p the Permission object to compare
  517        *
  518        * @return true if "permission" is a proper subset of a permission in
  519        * the set, false if not.
  520        */
  521   
  522       public boolean implies(Permission permission)
  523       {
  524           if (! (permission instanceof PropertyPermission))
  525                   return false;
  526   
  527           PropertyPermission pp = (PropertyPermission) permission;
  528           PropertyPermission x;
  529   
  530           int desired = pp.getMask();
  531           int effective = 0;
  532   
  533           // short circuit if the "*" Permission was added
  534           if (all_allowed) {
  535               synchronized (this) {
  536                   x = (PropertyPermission) perms.get("*");
  537               }
  538               if (x != null) {
  539                   effective |= x.getMask();
  540                   if ((effective & desired) == desired)
  541                       return true;
  542               }
  543           }
  544   
  545           // strategy:
  546           // Check for full match first. Then work our way up the
  547           // name looking for matches on a.b.*
  548   
  549           String name = pp.getName();
  550           //System.out.println("check "+name);
  551   
  552           synchronized (this) {
  553               x = (PropertyPermission) perms.get(name);
  554           }
  555   
  556           if (x != null) {
  557               // we have a direct hit!
  558               effective |= x.getMask();
  559               if ((effective & desired) == desired)
  560                   return true;
  561           }
  562   
  563           // work our way up the tree...
  564           int last, offset;
  565   
  566           offset = name.length()-1;
  567   
  568           while ((last = name.lastIndexOf(".", offset)) != -1) {
  569   
  570               name = name.substring(0, last+1) + "*";
  571               //System.out.println("check "+name);
  572               synchronized (this) {
  573                   x = (PropertyPermission) perms.get(name);
  574               }
  575   
  576               if (x != null) {
  577                   effective |= x.getMask();
  578                   if ((effective & desired) == desired)
  579                       return true;
  580               }
  581               offset = last -1;
  582           }
  583   
  584           // we don't have to check for "*" as it was already checked
  585           // at the top (all_allowed), so we just return false
  586           return false;
  587       }
  588   
  589       /**
  590        * Returns an enumeration of all the PropertyPermission objects in the
  591        * container.
  592        *
  593        * @return an enumeration of all the PropertyPermission objects.
  594        */
  595   
  596       public Enumeration elements() {
  597           // Convert Iterator of Map values into an Enumeration
  598           synchronized (this) {
  599               return Collections.enumeration(perms.values());
  600           }
  601       }
  602   
  603       private static final long serialVersionUID = 7015263904581634791L;
  604   
  605       // Need to maintain serialization interoperability with earlier releases,
  606       // which had the serializable field:
  607       //
  608       // Table of permissions.
  609       //
  610       // @serial
  611       //
  612       // private Hashtable permissions;
  613       /**
  614        * @serialField permissions java.util.Hashtable
  615        *     A table of the PropertyPermissions.
  616        * @serialField all_allowed boolean
  617        *     boolean saying if "*" is in the collection.
  618        */
  619       private static final ObjectStreamField[] serialPersistentFields = {
  620           new ObjectStreamField("permissions", Hashtable.class),
  621           new ObjectStreamField("all_allowed", Boolean.TYPE),
  622       };
  623   
  624       /**
  625        * @serialData Default fields.
  626        */
  627       /*
  628        * Writes the contents of the perms field out as a Hashtable for
  629        * serialization compatibility with earlier releases. all_allowed
  630        * unchanged.
  631        */
  632       private void writeObject(ObjectOutputStream out) throws IOException {
  633           // Don't call out.defaultWriteObject()
  634   
  635           // Copy perms into a Hashtable
  636           Hashtable permissions = new Hashtable(perms.size()*2);
  637           synchronized (this) {
  638               permissions.putAll(perms);
  639           }
  640   
  641           // Write out serializable fields
  642           ObjectOutputStream.PutField pfields = out.putFields();
  643           pfields.put("all_allowed", all_allowed);
  644           pfields.put("permissions", permissions);
  645           out.writeFields();
  646       }
  647   
  648       /*
  649        * Reads in a Hashtable of PropertyPermissions and saves them in the
  650        * perms field. Reads in all_allowed.
  651        */
  652       private void readObject(ObjectInputStream in) throws IOException,
  653       ClassNotFoundException {
  654           // Don't call defaultReadObject()
  655   
  656           // Read in serialized fields
  657           ObjectInputStream.GetField gfields = in.readFields();
  658   
  659           // Get all_allowed
  660           all_allowed = gfields.get("all_allowed", false);
  661   
  662           // Get permissions
  663           Hashtable permissions = (Hashtable)gfields.get("permissions", null);
  664           perms = new HashMap(permissions.size()*2);
  665           perms.putAll(permissions);
  666       }
  667   }

Home » openjdk-7 » java » util » [javadoc | source]