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 
ExecOptionPermission(String name)57     public ExecOptionPermission(String name) {
58         super(name);
59         init(name);
60     }
61 
ExecOptionPermission(String name, String actions)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      */
implies(Permission p)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      */
equals(Object obj)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      */
hashCode()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      */
getActions()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      */
newPermissionCollection()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      */
readObject(java.io.ObjectInputStream s)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      */
init(String name)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          */
ExecOptionPermissionCollection()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 
add(Permission permission)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          */
implies(Permission permission)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 
elements()343         public Enumeration<Permission> elements()
344         {
345             return permissions.elements();
346         }
347     }
348 }
349