001: /*
002: * @(#)IxcPermission.java 1.7 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026:
027: package javax.microedition.xlet.ixc;
028:
029: import java.io.IOException;
030: import java.util.ArrayList;
031: import java.util.Collections;
032: import java.util.Enumeration;
033: import java.util.List;
034: import java.util.Vector;
035: import java.security.Permission;
036: import java.security.PermissionCollection;
037:
038: public final class IxcPermission extends Permission {
039:
040: /**
041: * Bind action.
042: */
043: private final static int BIND = 0x1;
044: /**
045: * Lookup action.
046: */
047: private final static int LOOKUP = 0x2;
048:
049: /**
050: * All actions (bind,lookup)
051: */
052: private final static int ALL = BIND | LOOKUP;
053:
054: /**
055: * No actions.
056: */
057: private final static int NONE = 0x0;
058:
059: // the actions mask
060: private transient int mask;
061:
062: // static Strings used by init(int mask)
063: private static final char WILD_CHAR = '*';
064:
065: // canonicalized dir path. In the case of
066: // directories, it is the name "/blah/*" without
067: // the last character (the "*" or "-").
068: private transient String cpath;
069:
070: /**
071: * the actions string.
072: *
073: * @serial
074: */
075: private String actions; // Left null as long as possible, then
076: // created and re-used in the getAction function.
077:
078: // does path include a wildcard?
079: private transient boolean wildcard;
080:
081: /**
082: public String toString() {
083: StringBuffer sb = new StringBuffer();
084: sb.append("***\n");
085: sb.append("cpath = "+cpath+"\n");
086: sb.append("mask = "+mask+"\n");
087: sb.append("actions = "+getActions()+"\n");
088: sb.append("wildcard = "+wildcard+"\n");
089: sb.append("***\n");
090: return sb.toString();
091: }
092: **/
093:
094: /*
095: * Initialize a IxcPermission object. Common to all constructors.
096: * Also called during de-serialization.
097: *
098: * @param mask the actions mask to use.
099: */
100: private void init(int mask) {
101: if ((mask & ALL) != mask)
102: throw new IllegalArgumentException("invalid actions mask");
103: if (mask == NONE)
104: throw new IllegalArgumentException("invalid actions mask");
105: if ((cpath = getName()) == null)
106: throw new NullPointerException("name can't be null");
107:
108: this .mask = mask;
109: int len = cpath.length();
110: char last = ((len > 0) ? cpath.charAt(len - 1) : 0);
111:
112: if (last == WILD_CHAR
113: && (len == 1 || cpath.charAt(len - 2) == '/')) { //6254827
114: wildcard = true;
115: cpath = cpath.substring(0, --len);
116: }
117: }
118:
119: /**
120: * Converts an actions String to an actions mask.
121: *
122: * @param action the action string.
123: * @return the actions mask.
124: */
125: private static int getMask(String actions) {
126: int mask = NONE;
127:
128: if (actions == null) {
129: return mask;
130: }
131:
132: char[] a = actions.toCharArray();
133:
134: int i = a.length - 1;
135: if (i < 0)
136: return mask;
137:
138: while (i != -1) {
139: char c;
140:
141: // skip whitespace
142: while ((i != -1)
143: && ((c = a[i]) == ' ' || c == '\r' || c == '\n'
144: || c == '\f' || c == '\t'))
145: i--;
146:
147: // check for the known strings
148: int matchlen;
149: if (i >= 3 && (a[i - 3] == 'b' || a[i - 3] == 'B')
150: && (a[i - 2] == 'i' || a[i - 2] == 'I')
151: && (a[i - 1] == 'n' || a[i - 1] == 'N')
152: && (a[i] == 'd' || a[i] == 'D')) {
153: matchlen = 4;
154: mask |= BIND;
155:
156: } else if (i >= 5 && (a[i - 5] == 'l' || a[i - 5] == 'L')
157: && (a[i - 4] == 'o' || a[i - 4] == 'O')
158: && (a[i - 3] == 'o' || a[i - 3] == 'O')
159: && (a[i - 2] == 'k' || a[i - 2] == 'K')
160: && (a[i - 1] == 'u' || a[i - 1] == 'U')
161: && (a[i] == 'p' || a[i] == 'P')) {
162: matchlen = 6;
163: mask |= LOOKUP;
164:
165: } else {
166: // parse error
167: throw new IllegalArgumentException(
168: "invalid permission: " + actions);
169: }
170:
171: // make sure we didn't just match the tail of a word
172: // like "ackbarfaccept". Also, skip to the comma.
173: boolean seencomma = false;
174: while (i >= matchlen && !seencomma) {
175: switch (a[i - matchlen]) {
176: case ',':
177: seencomma = true;
178: /*FALLTHROUGH*/
179: case ' ':
180: case '\r':
181: case '\n':
182: case '\f':
183: case '\t':
184: break;
185: default:
186: throw new IllegalArgumentException(
187: "invalid permission: " + actions);
188: }
189: i--;
190: }
191:
192: // point i at the location of the comma minus one (or -1).
193: i -= matchlen;
194: }
195:
196: return mask;
197: }
198:
199: /**
200: * Return the current action mask. Used by the IxcPermissionCollection.
201: *
202: * @return the actions mask.
203: */
204: int getMask() {
205: return mask;
206: }
207:
208: public IxcPermission(String name, String actions) {
209: super (name);
210: init(getMask(actions));
211: }
212:
213: // package private for use by the IxcPermissionCollection add method
214: IxcPermission(String path, int mask) {
215: super (path);
216: init(mask);
217: }
218:
219: public boolean implies(Permission p) {
220: if (!(p instanceof IxcPermission))
221: return false;
222:
223: IxcPermission that = (IxcPermission) p;
224:
225: // we get the effective mask. i.e., the "and" of this and that.
226: // They must be equal to that.mask for implies to return true.
227:
228: return ((this .mask & that.mask) == that.mask)
229: && impliesIgnoreMask(that);
230: }
231:
232: /**
233: * Checks if the Permission's actions are a proper subset of the
234: * this object's actions. Returns the effective mask iff the
235: * this IxcPermission's path also implies that IxcPermission's path.
236: *
237: * @param that the IxcPermission to check against.
238: * @param exact return immediatly if the masks are not equal
239: * @return the effective mask
240: */
241: boolean impliesIgnoreMask(IxcPermission that) {
242: if (this .wildcard) {
243: if (that.wildcard) {
244: // if the permission passed in is a directory
245: // specification, make sure that a non-recursive
246: // permission (i.e., this object) can't imply a recursive
247: // permission.
248: if (this .cpath.equals(that.cpath))
249: return true;
250: else if (this .cpath.length() == 0)
251: return true;
252: else
253: // A/B/* implies A/B/C/*
254: // A/*/D is not a valid wildcard
255: return (that.cpath.indexOf(this .cpath) == 0 && that.cpath
256: .length() > this .cpath.length());
257: } else {
258: int last = that.cpath.lastIndexOf('/'); //6254827
259: if (last == -1) {
260: // Check for the wildcard instead of returning
261: // false blindly
262: return (this .cpath.length() == 0);
263: } else {
264: // this.cpath.equals(that.cpath.substring(0, last+1));
265: // Use regionMatches to avoid creating new string
266: // A/B/* implies A/B/C
267: return (this .cpath.length() <= (last + 1))
268: && this .cpath.regionMatches(0, that.cpath,
269: 0, this .cpath.length());
270: //this.cpath.regionMatches(0, that.cpath, 0, last+1);
271: }
272: }
273:
274: } else {
275: return (this .cpath.equals(that.cpath));
276:
277: }
278: }
279:
280: public boolean equals(Object obj) {
281: if (obj == this )
282: return true;
283: if (!(obj instanceof IxcPermission))
284: return false;
285:
286: IxcPermission that = (IxcPermission) obj;
287: return ((this .mask == that.mask)
288: && this .cpath.equals(that.cpath) && (this .wildcard == that.wildcard));
289: }
290:
291: public int hashCode() {
292: return this .cpath.hashCode();
293: }
294:
295: private static String getActions(int mask) {
296: StringBuffer sb = new StringBuffer();
297: boolean comma = false;
298:
299: if ((mask & BIND) == BIND) {
300: comma = true;
301: sb.append("bind");
302: }
303:
304: if ((mask & LOOKUP) == LOOKUP) {
305: if (comma)
306: sb.append(',');
307: else
308: comma = true;
309: sb.append("lookup");
310: }
311:
312: return sb.toString();
313: }
314:
315: public String getActions() {
316: if (actions == null)
317: actions = getActions(this .mask);
318:
319: return actions;
320: }
321:
322: public java.security.PermissionCollection newPermissionCollection() {
323: return new IxcPermissionCollection();
324: }
325: }
326:
327: final class IxcPermissionCollection extends PermissionCollection {
328:
329: // Not serialized; see serialization section at end of class
330: private transient List perms;
331:
332: /**
333: * Create an empty IxcPermissions object.
334: */
335: public IxcPermissionCollection() {
336: perms = new ArrayList();
337: }
338:
339: /**
340: * Adds a permission to the IxcPermissions. The key for the hash is
341: * permission.path.
342: *
343: * @param permission the Permission object to add.
344: * @exception IllegalArgumentException - if the permission is not a
345: * IxcPermission
346: * @exception SecurityException - if this IxcPermissionCollection object
347: * has been marked readonly
348: */
349:
350: public void add(Permission permission) {
351: if (!(permission instanceof IxcPermission))
352: throw new IllegalArgumentException("invalid permission: "
353: + permission);
354: if (isReadOnly())
355: throw new SecurityException(
356: "attempt to add a Permission to a readonly PermissionCollection");
357:
358: // No need to synchronize because all adds are done sequentially
359: // before any implies() calls
360: perms.add(permission);
361: }
362:
363: /**
364: * Check and see if this set of permissions implies the permissions
365: * expressed in "permission".
366: *
367: * @param p the Permission object to compare
368: * @return true if "permission" is a proper subset of a permission in
369: * the set, false if not.
370: */
371:
372: public boolean implies(Permission permission) {
373: if (!(permission instanceof IxcPermission))
374: return false;
375:
376: IxcPermission fp = (IxcPermission) permission;
377:
378: int desired = fp.getMask();
379: int effective = 0;
380: int needed = desired;
381:
382: int len = perms.size();
383: for (int i = 0; i < len; i++) {
384: IxcPermission x = (IxcPermission) perms.get(i);
385: if (((needed & x.getMask()) != 0)
386: && x.impliesIgnoreMask(fp)) {
387: effective |= x.getMask();
388: if ((effective & desired) == desired)
389: return true;
390: needed = (desired ^ effective);
391: }
392: }
393:
394: return false;
395: }
396:
397: /**
398: * Returns an enumeration of all the IxcPermission objects in the
399: * container.
400: *
401: * @return an enumeration of all the IxcPermission objects.
402: */
403:
404: public Enumeration elements() {
405: // Convert Iterator into Enumeration
406: return Collections.enumeration(perms);
407: }
408: }
|