1 /*
   2  * Copyright (c) 2000, 2012, 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 com.sun.rmi.rmid;
  27 
  28 import java.security.*;
  29 import java.io.*;
  30 import java.util.*;
  31 
  32 /**
  33  * The ExecOptionPermission class represents permission for rmid to use
  34  * a specific command-line option when launching an activation group.
  35  *
  36  * @author Ann Wollrath
  37  *
  38  * @serial exclude
  39  */
  40 public final class ExecOptionPermission extends Permission
  41 {
  42     /**
  43      * does this permission have a wildcard at the end?
  44      */
  45     private transient boolean wildcard;
  46 
  47     /**
  48      * the name without the wildcard on the end
  49      */
  50     private transient String name;
  51 
  52     /**
  53      * UID for serialization
  54      */
  55     private static final long serialVersionUID = 5842294756823092756L;
  56 
  57     public ExecOptionPermission(String name) {
  58         super(name);
  59         init(name);
  60     }
  61 
  62     public ExecOptionPermission(String name, String actions) {
  63         this(name);
  64     }
  65 
  66     /**
  67      * Checks if the specified permission is "implied" by
  68      * this object.
  69      * <P>
  70      * More specifically, this method returns true if:
  71      * <ul>
  72      * <li> <i>p</i>'s class is the same as this object's class, and
  73      * <li> <i>p</i>'s name equals or (in the case of wildcards)
  74      *      is implied by this object's
  75      *      name. For example, "a.b.*" implies "a.b.c", and
  76      *      "a.b=*" implies "a.b=c"
  77      * </ul>
  78      *
  79      * @param p the permission to check against.
  80      *
  81      * @return true if the passed permission is equal to or
  82      * implied by this permission, false otherwise.
  83      */
  84     public boolean implies(Permission p) {
  85         if (!(p instanceof ExecOptionPermission))
  86             return false;
  87 
  88         ExecOptionPermission that = (ExecOptionPermission) p;
  89 
  90         if (this.wildcard) {
  91             if (that.wildcard) {
  92                 // one wildcard can imply another
  93                 return that.name.startsWith(name);
  94             } else {
  95                 // make sure p.name is longer so a.b.* doesn't imply a.b
  96                 return (that.name.length() > this.name.length()) &&
  97                     that.name.startsWith(this.name);
  98             }
  99         } else {
 100             if (that.wildcard) {
 101                 // a non-wildcard can't imply a wildcard
 102                 return false;
 103             } else {
 104                 return this.name.equals(that.name);
 105             }
 106         }
 107     }
 108 
 109     /**
 110      * Checks two ExecOptionPermission objects for equality.
 111      * Checks that <i>obj</i>'s class is the same as this object's class
 112      * and has the same name as this object.
 113      *
 114      * @param obj the object we are testing for equality with this object.
 115      * @return true if <i>obj</i> is an ExecOptionPermission, and has the same
 116      * name as this ExecOptionPermission object, false otherwise.
 117      */
 118     public boolean equals(Object obj) {
 119         if (obj == this)
 120             return true;
 121 
 122         if ((obj == null) || (obj.getClass() != getClass()))
 123             return false;
 124 
 125         ExecOptionPermission that = (ExecOptionPermission) obj;
 126 
 127         return this.getName().equals(that.getName());
 128     }
 129 
 130 
 131     /**
 132      * Returns the hash code value for this object.
 133      * The hash code used is the hash code of the name, that is,
 134      * <code>getName().hashCode()</code>, where <code>getName</code> is
 135      * from the Permission superclass.
 136      *
 137      * @return a hash code value for this object.
 138      */
 139     public int hashCode() {
 140         return this.getName().hashCode();
 141     }
 142 
 143     /**
 144      * Returns the canonical string representation of the actions.
 145      *
 146      * @return the canonical string representation of the actions.
 147      */
 148     public String getActions() {
 149         return "";
 150     }
 151 
 152     /**
 153      * Returns a new PermissionCollection object for storing
 154      * ExecOptionPermission objects.
 155      * <p>
 156      * An ExecOptionPermissionCollection stores a collection of
 157      * ExecOptionPermission permissions.
 158      *
 159      * <p>ExecOptionPermission objects must be stored in a manner that allows
 160      * them to be inserted in any order, but that also enables the
 161      * PermissionCollection <code>implies</code> method
 162      * to be implemented in an efficient (and consistent) manner.
 163      *
 164      * @return a new PermissionCollection object suitable for
 165      * storing ExecOptionPermissions.
 166      */
 167     public PermissionCollection newPermissionCollection() {
 168         return new ExecOptionPermissionCollection();
 169     }
 170 
 171     /**
 172      * readObject is called to restore the state of the ExecOptionPermission
 173      * from a stream.
 174      */
 175     private synchronized void readObject(java.io.ObjectInputStream s)
 176          throws IOException, ClassNotFoundException
 177     {
 178         s.defaultReadObject();
 179         // init is called to initialize the rest of the values.
 180         init(getName());
 181     }
 182 
 183     /**
 184      * Initialize a ExecOptionPermission object. Common to all constructors.
 185      * Also called during de-serialization.
 186      */
 187     private void init(String name)
 188     {
 189         if (name == null)
 190             throw new NullPointerException("name can't be null");
 191 
 192         if (name.isEmpty()) {
 193             throw new IllegalArgumentException("name can't be empty");
 194         }
 195 
 196         if (name.endsWith(".*") || name.endsWith("=*") || name.equals("*")) {
 197             wildcard = true;
 198             if (name.length() == 1) {
 199                 this.name = "";
 200             } else {
 201                 this.name = name.substring(0, name.length()-1);
 202             }
 203         } else {
 204             this.name = name;
 205         }
 206     }
 207 
 208     /**
 209      * A ExecOptionPermissionCollection stores a collection
 210      * of ExecOptionPermission permissions. ExecOptionPermission objects
 211      * must be stored in a manner that allows them to be inserted in any
 212      * order, but enable the implies function to evaluate the implies
 213      * method in an efficient (and consistent) manner.
 214      *
 215      * A ExecOptionPermissionCollection handles comparing a permission like
 216      * "a.b.c.d.e" * with a Permission such as "a.b.*", or "*".
 217      *
 218      * @serial include
 219      */
 220     private static class ExecOptionPermissionCollection
 221         extends PermissionCollection
 222         implements java.io.Serializable
 223     {
 224 
 225         private Hashtable<String, Permission> permissions;
 226         private boolean all_allowed; // true if "*" is in the collection
 227         private static final long serialVersionUID = -1242475729790124375L;
 228 
 229         /**
 230          * Create an empty ExecOptionPermissionCollection.
 231          */
 232         public ExecOptionPermissionCollection() {
 233             permissions = new Hashtable<>(11);
 234             all_allowed = false;
 235         }
 236 
 237         /**
 238          * Adds a permission to the collection. The key for the hash is
 239          * permission.name.
 240          *
 241          * @param permission the Permission object to add.
 242          *
 243          * @exception IllegalArgumentException - if the permission is not a
 244          *                                       ExecOptionPermission
 245          *
 246          * @exception SecurityException - if this ExecOptionPermissionCollection
 247          *                                object has been marked readonly
 248          */
 249 
 250         public void add(Permission permission)
 251         {
 252             if (! (permission instanceof ExecOptionPermission))
 253                 throw new IllegalArgumentException("invalid permission: "+
 254                                                    permission);
 255             if (isReadOnly())
 256                 throw new SecurityException("attempt to add a Permission to a readonly PermissionCollection");
 257 
 258             ExecOptionPermission p = (ExecOptionPermission) permission;
 259 
 260             permissions.put(p.getName(), permission);
 261             if (!all_allowed) {
 262                 if (p.getName().equals("*"))
 263                     all_allowed = true;
 264             }
 265         }
 266 
 267         /**
 268          * Check and see if this set of permissions implies the permissions
 269          * expressed in "permission".
 270          *
 271          * @param p the Permission object to compare
 272          *
 273          * @return true if "permission" is a proper subset of a permission in
 274          * the set, false if not.
 275          */
 276         public boolean implies(Permission permission)
 277         {
 278             if (! (permission instanceof ExecOptionPermission))
 279                 return false;
 280 
 281             ExecOptionPermission p = (ExecOptionPermission) permission;
 282 
 283             // short circuit if the "*" Permission was added
 284             if (all_allowed)
 285                 return true;
 286 
 287             // strategy:
 288             // Check for full match first. Then work our way up the
 289             // name looking for matches on a.b.*
 290 
 291             String pname = p.getName();
 292 
 293             Permission x = permissions.get(pname);
 294 
 295             if (x != null)
 296                 // we have a direct hit!
 297                 return x.implies(permission);
 298 
 299 
 300             // work our way up the tree...
 301             int last, offset;
 302 
 303             offset = pname.length() - 1;
 304 
 305             while ((last = pname.lastIndexOf('.', offset)) != -1) {
 306 
 307                 pname = pname.substring(0, last+1) + "*";
 308                 x = permissions.get(pname);
 309 
 310                 if (x != null) {
 311                     return x.implies(permission);
 312                 }
 313                 offset = last - 1;
 314             }
 315 
 316             // check for "=*" wildcard match
 317             pname = p.getName();
 318             offset = pname.length() - 1;
 319 
 320             while ((last = pname.lastIndexOf('=', offset)) != -1) {
 321 
 322                 pname = pname.substring(0, last+1) + "*";
 323                 x = permissions.get(pname);
 324 
 325                 if (x != null) {
 326                     return x.implies(permission);
 327                 }
 328                 offset = last - 1;
 329             }
 330 
 331             // we don't have to check for "*" as it was already checked
 332             // at the top (all_allowed), so we just return false
 333             return false;
 334         }
 335 
 336         /**
 337          * Returns an enumeration of all the ExecOptionPermission objects in the
 338          * container.
 339          *
 340          * @return an enumeration of all the ExecOptionPermission objects.
 341          */
 342 
 343         public Enumeration<Permission> elements()
 344         {
 345             return permissions.elements();
 346         }
 347     }
 348 }