blob: 762f5defc7c1bbd53746f05b3cf87a7272e249a7 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2002-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package javax.management;
27
28import java.io.IOException;
29import java.io.ObjectInputStream;
30import java.security.Permission;
31
32/**
33 * <p>Permission controlling access to MBeanServer operations. If a
34 * security manager has been set using {@link
35 * System#setSecurityManager}, most operations on the MBean Server
36 * require that the caller's permissions imply an MBeanPermission
37 * appropriate for the operation. This is described in detail in the
38 * documentation for the {@link MBeanServer} interface.</p>
39 *
40 * <p>As with other {@link Permission} objects, an MBeanPermission can
41 * represent either a permission that you <em>have</em> or a
42 * permission that you <em>need</em>. When a sensitive operation is
43 * being checked for permission, an MBeanPermission is constructed
44 * representing the permission you need. The operation is only
45 * allowed if the permissions you have {@link #implies imply} the
46 * permission you need.</p>
47 *
48 * <p>An MBeanPermission contains four items of information:</p>
49 *
50 * <ul>
51 *
52 * <li><p>The <em>action</em>. For a permission you need,
53 * this is one of the actions in the list <a
54 * href="#action-list">below</a>. For a permission you have, this is
55 * a comma-separated list of those actions, or <code>*</code>,
56 * representing all actions.</p>
57 *
58 * <p>The action is returned by {@link #getActions()}.</p>
59 *
60 * <li><p>The <em>class name</em>.</p>
61 *
62 * <p>For a permission you need, this is the class name of an MBean
63 * you are accessing, as returned by {@link
64 * MBeanServer#getMBeanInfo(ObjectName)
65 * MBeanServer.getMBeanInfo(name)}.{@link MBeanInfo#getClassName()
66 * getClassName()}. Certain operations do not reference a class name,
67 * in which case the class name is null.</p>
68 *
69 * <p>For a permission you have, this is either empty or a <em>class
70 * name pattern</em>. A class name pattern is a string following the
71 * Java conventions for dot-separated class names. It may end with
72 * "<code>.*</code>" meaning that the permission grants access to any
73 * class that begins with the string preceding "<code>.*</code>". For
74 * instance, "<code>javax.management.*</code>" grants access to
75 * <code>javax.management.MBeanServerDelegate</code> and
76 * <code>javax.management.timer.Timer</code>, among other classes.</p>
77 *
78 * <p>A class name pattern can also be empty or the single character
79 * "<code>*</code>", both of which grant access to any class.</p>
80 *
81 * <li><p>The <em>member</em>.</p>
82 *
83 * <p>For a permission you need, this is the name of the attribute or
84 * operation you are accessing. For operations that do not reference
85 * an attribute or operation, the member is null.</p>
86 *
87 * <p>For a permission you have, this is either the name of an attribute
88 * or operation you can access, or it is empty or the single character
89 * "<code>*</code>", both of which grant access to any member.</p>
90 *
91 * <li><p>The <em>object name</em>.</p>
92 *
93 * <p>For a permission you need, this is the {@link ObjectName} of the
94 * MBean you are accessing. For operations that do not reference a
95 * single MBean, it is null. It is never an object name pattern.</p>
96 *
97 * <p>For a permission you have, this is the {@link ObjectName} of the
98 * MBean or MBeans you can access. It may be an object name pattern
99 * to grant access to all MBeans whose names match the pattern. It
100 * may also be empty, which grants access to all MBeans whatever their
101 * name.</p>
102 *
103 * </ul>
104 *
105 * <p>If you have an MBeanPermission, it allows operations only if all
106 * four of the items match.</p>
107 *
108 * <p>The class name, member, and object name can be written together
109 * as a single string, which is the <em>name</em> of this permission.
110 * The name of the permission is the string returned by {@link
111 * Permission#getName() getName()}. The format of the string is:</p>
112 *
113 * <blockquote>
114 * <code>className#member[objectName]</code>
115 * </blockquote>
116 *
117 * <p>The object name is written using the usual syntax for {@link
118 * ObjectName}. It may contain any legal characters, including
119 * <code>]</code>. It is terminated by a <code>]</code> character
120 * that is the last character in the string.</p>
121 *
122 * <p>One or more of the <code>className</code>, <code>member</code>,
123 * or <code>objectName</code> may be omitted. If the
124 * <code>member</code> is omitted, the <code>#</code> may be too (but
125 * does not have to be). If the <code>objectName</code> is omitted,
126 * the <code>[]</code> may be too (but does not have to be). It is
127 * not legal to omit all three items, that is to have a <em>name</em>
128 * that is the empty string.</p>
129 *
130 * <p>One or more of the <code>className</code>, <code>member</code>,
131 * or <code>objectName</code> may be the character "<code>-</code>",
132 * which is equivalent to a null value. A null value is implied by
133 * any value (including another null value) but does not imply any
134 * other value.</p>
135 *
136 * <p><a name="action-list">The possible actions are these:</a></p>
137 *
138 * <ul>
139 * <li>addNotificationListener</li>
140 * <li>getAttribute</li>
141 * <li>getClassLoader</li>
142 * <li>getClassLoaderFor</li>
143 * <li>getClassLoaderRepository</li>
144 * <li>getDomains</li>
145 * <li>getMBeanInfo</li>
146 * <li>getObjectInstance</li>
147 * <li>instantiate</li>
148 * <li>invoke</li>
149 * <li>isInstanceOf</li>
150 * <li>queryMBeans</li>
151 * <li>queryNames</li>
152 * <li>registerMBean</li>
153 * <li>removeNotificationListener</li>
154 * <li>setAttribute</li>
155 * <li>unregisterMBean</li>
156 * </ul>
157 *
158 * <p>In a comma-separated list of actions, spaces are allowed before
159 * and after each action.</p>
160 *
161 * @since 1.5
162 */
163public class MBeanPermission extends Permission {
164
165 private static final long serialVersionUID = -2416928705275160661L;
166
167 /**
168 * Actions list.
169 */
170 private static final int AddNotificationListener = 0x00001;
171 private static final int GetAttribute = 0x00002;
172 private static final int GetClassLoader = 0x00004;
173 private static final int GetClassLoaderFor = 0x00008;
174 private static final int GetClassLoaderRepository = 0x00010;
175 private static final int GetDomains = 0x00020;
176 private static final int GetMBeanInfo = 0x00040;
177 private static final int GetObjectInstance = 0x00080;
178 private static final int Instantiate = 0x00100;
179 private static final int Invoke = 0x00200;
180 private static final int IsInstanceOf = 0x00400;
181 private static final int QueryMBeans = 0x00800;
182 private static final int QueryNames = 0x01000;
183 private static final int RegisterMBean = 0x02000;
184 private static final int RemoveNotificationListener = 0x04000;
185 private static final int SetAttribute = 0x08000;
186 private static final int UnregisterMBean = 0x10000;
187
188 /**
189 * No actions.
190 */
191 private static final int NONE = 0x00000;
192
193 /**
194 * All actions.
195 */
196 private static final int ALL =
197 AddNotificationListener |
198 GetAttribute |
199 GetClassLoader |
200 GetClassLoaderFor |
201 GetClassLoaderRepository |
202 GetDomains |
203 GetMBeanInfo |
204 GetObjectInstance |
205 Instantiate |
206 Invoke |
207 IsInstanceOf |
208 QueryMBeans |
209 QueryNames |
210 RegisterMBean |
211 RemoveNotificationListener |
212 SetAttribute |
213 UnregisterMBean;
214
215 /**
216 * The actions string.
217 */
218 private String actions;
219
220 /**
221 * The actions mask.
222 */
223 private transient int mask;
224
225 /**
226 * The classname prefix that must match. If null, is implied by any
227 * classNamePrefix but does not imply any non-null classNamePrefix.
228 */
229 private transient String classNamePrefix;
230
231 /**
232 * True if classNamePrefix must match exactly. Otherwise, the
233 * className being matched must start with classNamePrefix.
234 */
235 private transient boolean classNameExactMatch;
236
237 /**
238 * The member that must match. If null, is implied by any member
239 * but does not imply any non-null member.
240 */
241 private transient String member;
242
243 /**
244 * The objectName that must match. If null, is implied by any
245 * objectName but does not imply any non-null objectName.
246 */
247 private transient ObjectName objectName;
248
249 /**
250 * Parse <code>actions</code> parameter.
251 */
252 private void parseActions() {
253
254 int mask;
255
256 if (actions == null)
257 throw new IllegalArgumentException("MBeanPermission: " +
258 "actions can't be null");
259 if (actions.equals(""))
260 throw new IllegalArgumentException("MBeanPermission: " +
261 "actions can't be empty");
262
263 mask = getMask(actions);
264
265 if ((mask & ALL) != mask)
266 throw new IllegalArgumentException("Invalid actions mask");
267 if (mask == NONE)
268 throw new IllegalArgumentException("Invalid actions mask");
269 this.mask = mask;
270 }
271
272 /**
273 * Parse <code>name</code> parameter.
274 */
275 private void parseName() {
276 String name = getName();
277
278 if (name == null)
279 throw new IllegalArgumentException("MBeanPermission name " +
280 "cannot be null");
281
282 if (name.equals(""))
283 throw new IllegalArgumentException("MBeanPermission name " +
284 "cannot be empty");
285
286 /* The name looks like "class#member[objectname]". We subtract
287 elements from the right as we parse, so after parsing the
288 objectname we have "class#member" and after parsing the
289 member we have "class". Each element is optional. */
290
291 // Parse ObjectName
292
293 int openingBracket = name.indexOf("[");
294 if (openingBracket == -1) {
295 // If "[on]" missing then ObjectName("*:*")
296 //
297 objectName = ObjectName.WILDCARD;
298 } else {
299 if (!name.endsWith("]")) {
300 throw new IllegalArgumentException("MBeanPermission: " +
301 "The ObjectName in the " +
302 "target name must be " +
303 "included in square " +
304 "brackets");
305 } else {
306 // Create ObjectName
307 //
308 try {
309 // If "[]" then ObjectName("*:*")
310 //
311 String on = name.substring(openingBracket + 1,
312 name.length() - 1);
313 if (on.equals(""))
314 objectName = ObjectName.WILDCARD;
315 else if (on.equals("-"))
316 objectName = null;
317 else
318 objectName = new ObjectName(on);
319 } catch (MalformedObjectNameException e) {
320 throw new IllegalArgumentException("MBeanPermission: " +
321 "The target name does " +
322 "not specify a valid " +
323 "ObjectName");
324 }
325 }
326
327 name = name.substring(0, openingBracket);
328 }
329
330 // Parse member
331
332 int poundSign = name.indexOf("#");
333
334 if (poundSign == -1)
335 setMember("*");
336 else {
337 String memberName = name.substring(poundSign + 1);
338 setMember(memberName);
339 name = name.substring(0, poundSign);
340 }
341
342 // Parse className
343
344 setClassName(name);
345 }
346
347 /**
348 * Assign fields based on className, member, and objectName
349 * parameters.
350 */
351 private void initName(String className, String member,
352 ObjectName objectName) {
353 setClassName(className);
354 setMember(member);
355 this.objectName = objectName;
356 }
357
358 private void setClassName(String className) {
359 if (className == null || className.equals("-")) {
360 classNamePrefix = null;
361 classNameExactMatch = false;
362 } else if (className.equals("") || className.equals("*")) {
363 classNamePrefix = "";
364 classNameExactMatch = false;
365 } else if (className.endsWith(".*")) {
366 // Note that we include the "." in the required prefix
367 classNamePrefix = className.substring(0, className.length() - 1);
368 classNameExactMatch = false;
369 } else {
370 classNamePrefix = className;
371 classNameExactMatch = true;
372 }
373 }
374
375 private void setMember(String member) {
376 if (member == null || member.equals("-"))
377 this.member = null;
378 else if (member.equals(""))
379 this.member = "*";
380 else
381 this.member = member;
382 }
383
384 /**
385 * <p>Create a new MBeanPermission object with the specified target name
386 * and actions.</p>
387 *
388 * <p>The target name is of the form
389 * "<code>className#member[objectName]</code>" where each part is
390 * optional. It must not be empty or null.</p>
391 *
392 * <p>The actions parameter contains a comma-separated list of the
393 * desired actions granted on the target name. It must not be
394 * empty or null.</p>
395 *
396 * @param name the triplet "className#member[objectName]".
397 * @param actions the action string.
398 *
399 * @exception IllegalArgumentException if the <code>name</code> or
400 * <code>actions</code> is invalid.
401 */
402 public MBeanPermission(String name, String actions) {
403 super(name);
404
405 parseName();
406
407 this.actions = actions;
408 parseActions();
409 }
410
411 /**
412 * <p>Create a new MBeanPermission object with the specified target name
413 * (class name, member, object name) and actions.</p>
414 *
415 * <p>The class name, member and object name parameters define a
416 * target name of the form
417 * "<code>className#member[objectName]</code>" where each part is
418 * optional. This will be the result of {@link #getName()} on the
419 * resultant MBeanPermission.</p>
420 *
421 * <p>The actions parameter contains a comma-separated list of the
422 * desired actions granted on the target name. It must not be
423 * empty or null.</p>
424 *
425 * @param className the class name to which this permission applies.
426 * May be null or <code>"-"</code>, which represents a class name
427 * that is implied by any class name but does not imply any other
428 * class name.
429 * @param member the member to which this permission applies. May
430 * be null or <code>"-"</code>, which represents a member that is
431 * implied by any member but does not imply any other member.
432 * @param objectName the object name to which this permission
433 * applies. May be null, which represents an object name that is
434 * implied by any object name but does not imply any other object
435 * name.
436 * @param actions the action string.
437 */
438 public MBeanPermission(String className,
439 String member,
440 ObjectName objectName,
441 String actions) {
442
443 super(makeName(className, member, objectName));
444 initName(className, member, objectName);
445
446 this.actions = actions;
447 parseActions();
448 }
449
450 private static String makeName(String className, String member,
451 ObjectName objectName) {
452 final StringBuilder name = new StringBuilder();
453 if (className == null)
454 className = "-";
455 name.append(className);
456 if (member == null)
457 member = "-";
458 name.append("#" + member);
459 if (objectName == null)
460 name.append("[-]");
461 else
462 name.append("[").append(objectName.getCanonicalName()).append("]");
463
464 /* In the interests of legibility for Permission.toString(), we
465 transform the empty string into "*". */
466 if (name.length() == 0)
467 return "*";
468 else
469 return name.toString();
470 }
471
472 /**
473 * Returns the "canonical string representation" of the actions. That is,
474 * this method always returns present actions in alphabetical order.
475 *
476 * @return the canonical string representation of the actions.
477 */
478 public String getActions() {
479
480 if (actions == null)
481 actions = getActions(this.mask);
482
483 return actions;
484 }
485
486 /**
487 * Returns the "canonical string representation"
488 * of the actions from the mask.
489 */
490 private static String getActions(int mask) {
491 final StringBuilder sb = new StringBuilder();
492 boolean comma = false;
493
494 if ((mask & AddNotificationListener) == AddNotificationListener) {
495 comma = true;
496 sb.append("addNotificationListener");
497 }
498
499 if ((mask & GetAttribute) == GetAttribute) {
500 if (comma) sb.append(',');
501 else comma = true;
502 sb.append("getAttribute");
503 }
504
505 if ((mask & GetClassLoader) == GetClassLoader) {
506 if (comma) sb.append(',');
507 else comma = true;
508 sb.append("getClassLoader");
509 }
510
511 if ((mask & GetClassLoaderFor) == GetClassLoaderFor) {
512 if (comma) sb.append(',');
513 else comma = true;
514 sb.append("getClassLoaderFor");
515 }
516
517 if ((mask & GetClassLoaderRepository) == GetClassLoaderRepository) {
518 if (comma) sb.append(',');
519 else comma = true;
520 sb.append("getClassLoaderRepository");
521 }
522
523 if ((mask & GetDomains) == GetDomains) {
524 if (comma) sb.append(',');
525 else comma = true;
526 sb.append("getDomains");
527 }
528
529 if ((mask & GetMBeanInfo) == GetMBeanInfo) {
530 if (comma) sb.append(',');
531 else comma = true;
532 sb.append("getMBeanInfo");
533 }
534
535 if ((mask & GetObjectInstance) == GetObjectInstance) {
536 if (comma) sb.append(',');
537 else comma = true;
538 sb.append("getObjectInstance");
539 }
540
541 if ((mask & Instantiate) == Instantiate) {
542 if (comma) sb.append(',');
543 else comma = true;
544 sb.append("instantiate");
545 }
546
547 if ((mask & Invoke) == Invoke) {
548 if (comma) sb.append(',');
549 else comma = true;
550 sb.append("invoke");
551 }
552
553 if ((mask & IsInstanceOf) == IsInstanceOf) {
554 if (comma) sb.append(',');
555 else comma = true;
556 sb.append("isInstanceOf");
557 }
558
559 if ((mask & QueryMBeans) == QueryMBeans) {
560 if (comma) sb.append(',');
561 else comma = true;
562 sb.append("queryMBeans");
563 }
564
565 if ((mask & QueryNames) == QueryNames) {
566 if (comma) sb.append(',');
567 else comma = true;
568 sb.append("queryNames");
569 }
570
571 if ((mask & RegisterMBean) == RegisterMBean) {
572 if (comma) sb.append(',');
573 else comma = true;
574 sb.append("registerMBean");
575 }
576
577 if ((mask & RemoveNotificationListener) == RemoveNotificationListener) {
578 if (comma) sb.append(',');
579 else comma = true;
580 sb.append("removeNotificationListener");
581 }
582
583 if ((mask & SetAttribute) == SetAttribute) {
584 if (comma) sb.append(',');
585 else comma = true;
586 sb.append("setAttribute");
587 }
588
589 if ((mask & UnregisterMBean) == UnregisterMBean) {
590 if (comma) sb.append(',');
591 else comma = true;
592 sb.append("unregisterMBean");
593 }
594
595 return sb.toString();
596 }
597
598 /**
599 * Returns the hash code value for this object.
600 *
601 * @return a hash code value for this object.
602 */
603 public int hashCode() {
604 return this.getName().hashCode() + this.getActions().hashCode();
605 }
606
607 /**
608 * Converts an action String to an integer action mask.
609 *
610 * @param action the action string.
611 * @return the action mask.
612 */
613 private static int getMask(String action) {
614
615 /*
616 * BE CAREFUL HERE! PARSING ORDER IS IMPORTANT IN THIS ALGORITHM.
617 *
618 * The 'string length' test must be performed for the lengthiest
619 * strings first.
620 *
621 * In this permission if the "unregisterMBean" string length test is
622 * performed after the "registerMBean" string length test the algorithm
623 * considers the 'unregisterMBean' action as being the 'registerMBean'
624 * action and a parsing error is returned.
625 */
626
627 int mask = NONE;
628
629 if (action == null) {
630 return mask;
631 }
632
633 if (action.equals("*")) {
634 return ALL;
635 }
636
637 char[] a = action.toCharArray();
638
639 int i = a.length - 1;
640 if (i < 0)
641 return mask;
642
643 while (i != -1) {
644 char c;
645
646 // skip whitespace
647 while ((i!=-1) && ((c = a[i]) == ' ' ||
648 c == '\r' ||
649 c == '\n' ||
650 c == '\f' ||
651 c == '\t'))
652 i--;
653
654 // check for the known strings
655 int matchlen;
656
657 if (i >= 25 && /* removeNotificationListener */
658 (a[i-25] == 'r') &&
659 (a[i-24] == 'e') &&
660 (a[i-23] == 'm') &&
661 (a[i-22] == 'o') &&
662 (a[i-21] == 'v') &&
663 (a[i-20] == 'e') &&
664 (a[i-19] == 'N') &&
665 (a[i-18] == 'o') &&
666 (a[i-17] == 't') &&
667 (a[i-16] == 'i') &&
668 (a[i-15] == 'f') &&
669 (a[i-14] == 'i') &&
670 (a[i-13] == 'c') &&
671 (a[i-12] == 'a') &&
672 (a[i-11] == 't') &&
673 (a[i-10] == 'i') &&
674 (a[i-9] == 'o') &&
675 (a[i-8] == 'n') &&
676 (a[i-7] == 'L') &&
677 (a[i-6] == 'i') &&
678 (a[i-5] == 's') &&
679 (a[i-4] == 't') &&
680 (a[i-3] == 'e') &&
681 (a[i-2] == 'n') &&
682 (a[i-1] == 'e') &&
683 (a[i] == 'r')) {
684 matchlen = 26;
685 mask |= RemoveNotificationListener;
686 } else if (i >= 23 && /* getClassLoaderRepository */
687 (a[i-23] == 'g') &&
688 (a[i-22] == 'e') &&
689 (a[i-21] == 't') &&
690 (a[i-20] == 'C') &&
691 (a[i-19] == 'l') &&
692 (a[i-18] == 'a') &&
693 (a[i-17] == 's') &&
694 (a[i-16] == 's') &&
695 (a[i-15] == 'L') &&
696 (a[i-14] == 'o') &&
697 (a[i-13] == 'a') &&
698 (a[i-12] == 'd') &&
699 (a[i-11] == 'e') &&
700 (a[i-10] == 'r') &&
701 (a[i-9] == 'R') &&
702 (a[i-8] == 'e') &&
703 (a[i-7] == 'p') &&
704 (a[i-6] == 'o') &&
705 (a[i-5] == 's') &&
706 (a[i-4] == 'i') &&
707 (a[i-3] == 't') &&
708 (a[i-2] == 'o') &&
709 (a[i-1] == 'r') &&
710 (a[i] == 'y')) {
711 matchlen = 24;
712 mask |= GetClassLoaderRepository;
713 } else if (i >= 22 && /* addNotificationListener */
714 (a[i-22] == 'a') &&
715 (a[i-21] == 'd') &&
716 (a[i-20] == 'd') &&
717 (a[i-19] == 'N') &&
718 (a[i-18] == 'o') &&
719 (a[i-17] == 't') &&
720 (a[i-16] == 'i') &&
721 (a[i-15] == 'f') &&
722 (a[i-14] == 'i') &&
723 (a[i-13] == 'c') &&
724 (a[i-12] == 'a') &&
725 (a[i-11] == 't') &&
726 (a[i-10] == 'i') &&
727 (a[i-9] == 'o') &&
728 (a[i-8] == 'n') &&
729 (a[i-7] == 'L') &&
730 (a[i-6] == 'i') &&
731 (a[i-5] == 's') &&
732 (a[i-4] == 't') &&
733 (a[i-3] == 'e') &&
734 (a[i-2] == 'n') &&
735 (a[i-1] == 'e') &&
736 (a[i] == 'r')) {
737 matchlen = 23;
738 mask |= AddNotificationListener;
739 } else if (i >= 16 && /* getClassLoaderFor */
740 (a[i-16] == 'g') &&
741 (a[i-15] == 'e') &&
742 (a[i-14] == 't') &&
743 (a[i-13] == 'C') &&
744 (a[i-12] == 'l') &&
745 (a[i-11] == 'a') &&
746 (a[i-10] == 's') &&
747 (a[i-9] == 's') &&
748 (a[i-8] == 'L') &&
749 (a[i-7] == 'o') &&
750 (a[i-6] == 'a') &&
751 (a[i-5] == 'd') &&
752 (a[i-4] == 'e') &&
753 (a[i-3] == 'r') &&
754 (a[i-2] == 'F') &&
755 (a[i-1] == 'o') &&
756 (a[i] == 'r')) {
757 matchlen = 17;
758 mask |= GetClassLoaderFor;
759 } else if (i >= 16 && /* getObjectInstance */
760 (a[i-16] == 'g') &&
761 (a[i-15] == 'e') &&
762 (a[i-14] == 't') &&
763 (a[i-13] == 'O') &&
764 (a[i-12] == 'b') &&
765 (a[i-11] == 'j') &&
766 (a[i-10] == 'e') &&
767 (a[i-9] == 'c') &&
768 (a[i-8] == 't') &&
769 (a[i-7] == 'I') &&
770 (a[i-6] == 'n') &&
771 (a[i-5] == 's') &&
772 (a[i-4] == 't') &&
773 (a[i-3] == 'a') &&
774 (a[i-2] == 'n') &&
775 (a[i-1] == 'c') &&
776 (a[i] == 'e')) {
777 matchlen = 17;
778 mask |= GetObjectInstance;
779 } else if (i >= 14 && /* unregisterMBean */
780 (a[i-14] == 'u') &&
781 (a[i-13] == 'n') &&
782 (a[i-12] == 'r') &&
783 (a[i-11] == 'e') &&
784 (a[i-10] == 'g') &&
785 (a[i-9] == 'i') &&
786 (a[i-8] == 's') &&
787 (a[i-7] == 't') &&
788 (a[i-6] == 'e') &&
789 (a[i-5] == 'r') &&
790 (a[i-4] == 'M') &&
791 (a[i-3] == 'B') &&
792 (a[i-2] == 'e') &&
793 (a[i-1] == 'a') &&
794 (a[i] == 'n')) {
795 matchlen = 15;
796 mask |= UnregisterMBean;
797 } else if (i >= 13 && /* getClassLoader */
798 (a[i-13] == 'g') &&
799 (a[i-12] == 'e') &&
800 (a[i-11] == 't') &&
801 (a[i-10] == 'C') &&
802 (a[i-9] == 'l') &&
803 (a[i-8] == 'a') &&
804 (a[i-7] == 's') &&
805 (a[i-6] == 's') &&
806 (a[i-5] == 'L') &&
807 (a[i-4] == 'o') &&
808 (a[i-3] == 'a') &&
809 (a[i-2] == 'd') &&
810 (a[i-1] == 'e') &&
811 (a[i] == 'r')) {
812 matchlen = 14;
813 mask |= GetClassLoader;
814 } else if (i >= 12 && /* registerMBean */
815 (a[i-12] == 'r') &&
816 (a[i-11] == 'e') &&
817 (a[i-10] == 'g') &&
818 (a[i-9] == 'i') &&
819 (a[i-8] == 's') &&
820 (a[i-7] == 't') &&
821 (a[i-6] == 'e') &&
822 (a[i-5] == 'r') &&
823 (a[i-4] == 'M') &&
824 (a[i-3] == 'B') &&
825 (a[i-2] == 'e') &&
826 (a[i-1] == 'a') &&
827 (a[i] == 'n')) {
828 matchlen = 13;
829 mask |= RegisterMBean;
830 } else if (i >= 11 && /* getAttribute */
831 (a[i-11] == 'g') &&
832 (a[i-10] == 'e') &&
833 (a[i-9] == 't') &&
834 (a[i-8] == 'A') &&
835 (a[i-7] == 't') &&
836 (a[i-6] == 't') &&
837 (a[i-5] == 'r') &&
838 (a[i-4] == 'i') &&
839 (a[i-3] == 'b') &&
840 (a[i-2] == 'u') &&
841 (a[i-1] == 't') &&
842 (a[i] == 'e')) {
843 matchlen = 12;
844 mask |= GetAttribute;
845 } else if (i >= 11 && /* getMBeanInfo */
846 (a[i-11] == 'g') &&
847 (a[i-10] == 'e') &&
848 (a[i-9] == 't') &&
849 (a[i-8] == 'M') &&
850 (a[i-7] == 'B') &&
851 (a[i-6] == 'e') &&
852 (a[i-5] == 'a') &&
853 (a[i-4] == 'n') &&
854 (a[i-3] == 'I') &&
855 (a[i-2] == 'n') &&
856 (a[i-1] == 'f') &&
857 (a[i] == 'o')) {
858 matchlen = 12;
859 mask |= GetMBeanInfo;
860 } else if (i >= 11 && /* isInstanceOf */
861 (a[i-11] == 'i') &&
862 (a[i-10] == 's') &&
863 (a[i-9] == 'I') &&
864 (a[i-8] == 'n') &&
865 (a[i-7] == 's') &&
866 (a[i-6] == 't') &&
867 (a[i-5] == 'a') &&
868 (a[i-4] == 'n') &&
869 (a[i-3] == 'c') &&
870 (a[i-2] == 'e') &&
871 (a[i-1] == 'O') &&
872 (a[i] == 'f')) {
873 matchlen = 12;
874 mask |= IsInstanceOf;
875 } else if (i >= 11 && /* setAttribute */
876 (a[i-11] == 's') &&
877 (a[i-10] == 'e') &&
878 (a[i-9] == 't') &&
879 (a[i-8] == 'A') &&
880 (a[i-7] == 't') &&
881 (a[i-6] == 't') &&
882 (a[i-5] == 'r') &&
883 (a[i-4] == 'i') &&
884 (a[i-3] == 'b') &&
885 (a[i-2] == 'u') &&
886 (a[i-1] == 't') &&
887 (a[i] == 'e')) {
888 matchlen = 12;
889 mask |= SetAttribute;
890 } else if (i >= 10 && /* instantiate */
891 (a[i-10] == 'i') &&
892 (a[i-9] == 'n') &&
893 (a[i-8] == 's') &&
894 (a[i-7] == 't') &&
895 (a[i-6] == 'a') &&
896 (a[i-5] == 'n') &&
897 (a[i-4] == 't') &&
898 (a[i-3] == 'i') &&
899 (a[i-2] == 'a') &&
900 (a[i-1] == 't') &&
901 (a[i] == 'e')) {
902 matchlen = 11;
903 mask |= Instantiate;
904 } else if (i >= 10 && /* queryMBeans */
905 (a[i-10] == 'q') &&
906 (a[i-9] == 'u') &&
907 (a[i-8] == 'e') &&
908 (a[i-7] == 'r') &&
909 (a[i-6] == 'y') &&
910 (a[i-5] == 'M') &&
911 (a[i-4] == 'B') &&
912 (a[i-3] == 'e') &&
913 (a[i-2] == 'a') &&
914 (a[i-1] == 'n') &&
915 (a[i] == 's')) {
916 matchlen = 11;
917 mask |= QueryMBeans;
918 } else if (i >= 9 && /* getDomains */
919 (a[i-9] == 'g') &&
920 (a[i-8] == 'e') &&
921 (a[i-7] == 't') &&
922 (a[i-6] == 'D') &&
923 (a[i-5] == 'o') &&
924 (a[i-4] == 'm') &&
925 (a[i-3] == 'a') &&
926 (a[i-2] == 'i') &&
927 (a[i-1] == 'n') &&
928 (a[i] == 's')) {
929 matchlen = 10;
930 mask |= GetDomains;
931 } else if (i >= 9 && /* queryNames */
932 (a[i-9] == 'q') &&
933 (a[i-8] == 'u') &&
934 (a[i-7] == 'e') &&
935 (a[i-6] == 'r') &&
936 (a[i-5] == 'y') &&
937 (a[i-4] == 'N') &&
938 (a[i-3] == 'a') &&
939 (a[i-2] == 'm') &&
940 (a[i-1] == 'e') &&
941 (a[i] == 's')) {
942 matchlen = 10;
943 mask |= QueryNames;
944 } else if (i >= 5 && /* invoke */
945 (a[i-5] == 'i') &&
946 (a[i-4] == 'n') &&
947 (a[i-3] == 'v') &&
948 (a[i-2] == 'o') &&
949 (a[i-1] == 'k') &&
950 (a[i] == 'e')) {
951 matchlen = 6;
952 mask |= Invoke;
953 } else {
954 // parse error
955 throw new IllegalArgumentException("Invalid permission: " +
956 action);
957 }
958
959 // make sure we didn't just match the tail of a word
960 // like "ackbarfaccept". Also, skip to the comma.
961 boolean seencomma = false;
962 while (i >= matchlen && !seencomma) {
963 switch(a[i-matchlen]) {
964 case ',':
965 seencomma = true;
966 break;
967 case ' ': case '\r': case '\n':
968 case '\f': case '\t':
969 break;
970 default:
971 throw new IllegalArgumentException("Invalid permission: " +
972 action);
973 }
974 i--;
975 }
976
977 // point i at the location of the comma minus one (or -1).
978 i -= matchlen;
979 }
980
981 return mask;
982 }
983
984 /**
985 * <p>Checks if this MBeanPermission object "implies" the
986 * specified permission.</p>
987 *
988 * <p>More specifically, this method returns true if:</p>
989 *
990 * <ul>
991 *
992 * <li> <i>p</i> is an instance of MBeanPermission; and</li>
993 *
994 * <li> <i>p</i> has a null className or <i>p</i>'s className
995 * matches this object's className; and</li>
996 *
997 * <li> <i>p</i> has a null member or <i>p</i>'s member matches this
998 * object's member; and</li>
999 *
1000 * <li> <i>p</i> has a null object name or <i>p</i>'s
1001 * object name matches this object's object name; and</li>
1002 *
1003 * <li> <i>p</i>'s actions are a subset of this object's actions</li>
1004 *
1005 * </ul>
1006 *
1007 * <p>If this object's className is "<code>*</code>", <i>p</i>'s
1008 * className always matches it. If it is "<code>a.*</code>", <i>p</i>'s
1009 * className matches it if it begins with "<code>a.</code>".</p>
1010 *
1011 * <p>If this object's member is "<code>*</code>", <i>p</i>'s
1012 * member always matches it.</p>
1013 *
1014 * <p>If this object's objectName <i>n1</i> is an object name pattern,
1015 * <i>p</i>'s objectName <i>n2</i> matches it if
1016 * {@link ObjectName#equals <i>n1</i>.equals(<i>n2</i>)} or if
1017 * {@link ObjectName#apply <i>n1</i>.apply(<i>n2</i>)}.</p>
1018 *
1019 * <p>A permission that includes the <code>queryMBeans</code> action
1020 * is considered to include <code>queryNames</code> as well.</p>
1021 *
1022 * @param p the permission to check against.
1023 * @return true if the specified permission is implied by this object,
1024 * false if not.
1025 */
1026 public boolean implies(Permission p) {
1027 if (!(p instanceof MBeanPermission))
1028 return false;
1029
1030 MBeanPermission that = (MBeanPermission) p;
1031
1032 // Actions
1033 //
1034 // The actions in 'this' permission must be a
1035 // superset of the actions in 'that' permission
1036 //
1037
1038 /* "queryMBeans" implies "queryNames" */
1039 if ((this.mask & QueryMBeans) == QueryMBeans) {
1040 if (((this.mask | QueryNames) & that.mask) != that.mask) {
1041 //System.out.println("action [with QueryNames] does not imply");
1042 return false;
1043 }
1044 } else {
1045 if ((this.mask & that.mask) != that.mask) {
1046 //System.out.println("action does not imply");
1047 return false;
1048 }
1049 }
1050
1051 // Target name
1052 //
1053 // The 'className' check is true iff:
1054 // 1) the className in 'this' permission is omitted or "*", or
1055 // 2) the className in 'that' permission is omitted or "*", or
1056 // 3) the className in 'this' permission does pattern
1057 // matching with the className in 'that' permission.
1058 //
1059 // The 'member' check is true iff:
1060 // 1) the member in 'this' permission is omitted or "*", or
1061 // 2) the member in 'that' permission is omitted or "*", or
1062 // 3) the member in 'this' permission equals the member in
1063 // 'that' permission.
1064 //
1065 // The 'object name' check is true iff:
1066 // 1) the object name in 'this' permission is omitted or "*:*", or
1067 // 2) the object name in 'that' permission is omitted or "*:*", or
1068 // 3) the object name in 'this' permission does pattern
1069 // matching with the object name in 'that' permission.
1070 //
1071
1072 /* Check if this.className implies that.className.
1073
1074 If that.classNamePrefix is empty that means the className is
1075 irrelevant for this permission check. Otherwise, we do not
1076 expect that "that" contains a wildcard, since it is a
1077 needed permission. So we assume that.classNameExactMatch. */
1078
1079 if (that.classNamePrefix == null) {
1080 // bottom is implied
1081 } else if (this.classNamePrefix == null) {
1082 // bottom implies nothing but itself
1083 return false;
1084 } else if (this.classNameExactMatch) {
1085 if (!that.classNameExactMatch)
1086 return false; // exact never implies wildcard
1087 if (!that.classNamePrefix.equals(this.classNamePrefix))
1088 return false; // exact match fails
1089 } else {
1090 // prefix match, works even if "that" is also a wildcard
1091 // e.g. a.* implies a.* and a.b.*
1092 if (!that.classNamePrefix.startsWith(this.classNamePrefix))
1093 return false;
1094 }
1095
1096 /* Check if this.member implies that.member */
1097
1098 if (that.member == null) {
1099 // bottom is implied
1100 } else if (this.member == null) {
1101 // bottom implies nothing but itself
1102 return false;
1103 } else if (this.member.equals("*")) {
1104 // wildcard implies everything (including itself)
1105 } else if (!this.member.equals(that.member)) {
1106 return false;
1107 }
1108
1109 /* Check if this.objectName implies that.objectName */
1110
1111 if (that.objectName == null) {
1112 // bottom is implied
1113 } else if (this.objectName == null) {
1114 // bottom implies nothing but itself
1115 return false;
1116 } else if (!this.objectName.apply(that.objectName)) {
1117 /* ObjectName.apply returns false if that.objectName is a
1118 wildcard so we also allow equals for that case. This
1119 never happens during real permission checks, but means
1120 the implies relation is reflexive. */
1121 if (!this.objectName.equals(that.objectName))
1122 return false;
1123 }
1124
1125 return true;
1126 }
1127
1128 /**
1129 * Checks two MBeanPermission objects for equality. Checks
1130 * that <i>obj</i> is an MBeanPermission, and has the same
1131 * name and actions as this object.
1132 * <P>
1133 * @param obj the object we are testing for equality with this object.
1134 * @return true if obj is an MBeanPermission, and has the
1135 * same name and actions as this MBeanPermission object.
1136 */
1137 public boolean equals(Object obj) {
1138 if (obj == this)
1139 return true;
1140
1141 if (! (obj instanceof MBeanPermission))
1142 return false;
1143
1144 MBeanPermission that = (MBeanPermission) obj;
1145
1146 return (this.mask == that.mask) &&
1147 (this.getName().equals(that.getName()));
1148 }
1149
1150 /**
1151 * Deserialize this object based on its name and actions.
1152 */
1153 private void readObject(ObjectInputStream in)
1154 throws IOException, ClassNotFoundException {
1155 in.defaultReadObject();
1156 parseName();
1157 parseActions();
1158 }
1159}