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
26package com.sun.rmi.rmid;
27
28import java.security.*;
29import java.io.*;
30import 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 */
40public 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.equals("")) {
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}
349