1 /* 2 * Copyright (c) 1997, 2015, 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 java.security; 27 28 import java.util.ArrayList; 29 import java.util.List; 30 import sun.security.util.Debug; 31 import sun.security.util.SecurityConstants; 32 33 34 /** 35 * An AccessControlContext is used to make system resource access decisions 36 * based on the context it encapsulates. 37 * 38 * <p>More specifically, it encapsulates a context and 39 * has a single method, {@code checkPermission}, 40 * that is equivalent to the {@code checkPermission} method 41 * in the AccessController class, with one difference: The AccessControlContext 42 * {@code checkPermission} method makes access decisions based on the 43 * context it encapsulates, 44 * rather than that of the current execution thread. 45 * 46 * <p>Thus, the purpose of AccessControlContext is for those situations where 47 * a security check that should be made within a given context 48 * actually needs to be done from within a 49 * <i>different</i> context (for example, from within a worker thread). 50 * 51 * <p> An AccessControlContext is created by calling the 52 * {@code AccessController.getContext} method. 53 * The {@code getContext} method takes a "snapshot" 54 * of the current calling context, and places 55 * it in an AccessControlContext object, which it returns. A sample call is 56 * the following: 57 * 58 * <pre> 59 * AccessControlContext acc = AccessController.getContext() 60 * </pre> 61 * 62 * <p> 63 * Code within a different context can subsequently call the 64 * {@code checkPermission} method on the 65 * previously-saved AccessControlContext object. A sample call is the 66 * following: 67 * 68 * <pre> 69 * acc.checkPermission(permission) 70 * </pre> 71 * 72 * @see AccessController 73 * 74 * @author Roland Schemers 75 */ 76 77 public final class AccessControlContext { 78 79 private ProtectionDomain[] context; 80 // isPrivileged and isAuthorized are referenced by the VM - do not remove 81 // or change their names 82 private boolean isPrivileged; 83 private boolean isAuthorized = false; 84 85 // Note: This field is directly used by the virtual machine 86 // native codes. Don't touch it. 87 private AccessControlContext privilegedContext; 88 89 private DomainCombiner combiner = null; 90 91 // limited privilege scope 92 private Permission[] permissions; 93 private AccessControlContext parent; 94 private boolean isWrapped; 95 96 // is constrained by limited privilege scope? 97 private boolean isLimited; 98 private ProtectionDomain[] limitedContext; 99 100 private static boolean debugInit = false; 101 private static Debug debug = null; 102 103 static Debug getDebug() 104 { 105 if (debugInit) 106 return debug; 107 else { 108 if (Policy.isSet()) { 109 debug = Debug.getInstance("access"); 110 debugInit = true; 111 } 112 return debug; 113 } 114 } 115 116 /** 117 * Create an AccessControlContext with the given array of ProtectionDomains. 118 * Context must not be null. Duplicate domains will be removed from the 119 * context. 120 * 121 * @param context the ProtectionDomains associated with this context. 122 * The non-duplicate domains are copied from the array. Subsequent 123 * changes to the array will not affect this AccessControlContext. 124 * @throws NullPointerException if {@code context} is {@code null} 125 */ 126 public AccessControlContext(ProtectionDomain[] context) 127 { 128 if (context.length == 0) { 129 this.context = null; 130 } else if (context.length == 1) { 131 if (context[0] != null) { 132 this.context = context.clone(); 133 } else { 134 this.context = null; 135 } 136 } else { 137 List<ProtectionDomain> v = new ArrayList<>(context.length); 138 for (int i =0; i< context.length; i++) { 139 if ((context[i] != null) && (!v.contains(context[i]))) 140 v.add(context[i]); 141 } 142 if (!v.isEmpty()) { 143 this.context = new ProtectionDomain[v.size()]; 144 this.context = v.toArray(this.context); 145 } 146 } 147 } 148 149 /** 150 * Create a new {@code AccessControlContext} with the given 151 * {@code AccessControlContext} and {@code DomainCombiner}. 152 * This constructor associates the provided 153 * {@code DomainCombiner} with the provided 154 * {@code AccessControlContext}. 155 * 156 * @param acc the {@code AccessControlContext} associated 157 * with the provided {@code DomainCombiner}. 158 * 159 * @param combiner the {@code DomainCombiner} to be associated 160 * with the provided {@code AccessControlContext}. 161 * 162 * @exception NullPointerException if the provided 163 * {@code context} is {@code null}. 164 * 165 * @exception SecurityException if a security manager is installed and the 166 * caller does not have the "createAccessControlContext" 167 * {@link SecurityPermission} 168 * @since 1.3 169 */ 170 public AccessControlContext(AccessControlContext acc, 171 DomainCombiner combiner) { 172 173 this(acc, combiner, false); 174 } 175 176 /** 177 * package private to allow calls from ProtectionDomain without performing 178 * the security check for {@linkplain SecurityConstants.CREATE_ACC_PERMISSION} 179 * permission 180 */ 181 AccessControlContext(AccessControlContext acc, 182 DomainCombiner combiner, 183 boolean preauthorized) { 184 if (!preauthorized) { 185 SecurityManager sm = System.getSecurityManager(); 186 if (sm != null) { 187 sm.checkPermission(SecurityConstants.CREATE_ACC_PERMISSION); 188 this.isAuthorized = true; 189 } 190 } else { 191 this.isAuthorized = true; 192 } 193 194 this.context = acc.context; 195 196 // we do not need to run the combine method on the 197 // provided ACC. it was already "combined" when the 198 // context was originally retrieved. 199 // 200 // at this point in time, we simply throw away the old 201 // combiner and use the newly provided one. 202 this.combiner = combiner; 203 } 204 205 /** 206 * package private for AccessController 207 * 208 * This "argument wrapper" context will be passed as the actual context 209 * parameter on an internal doPrivileged() call used in the implementation. 210 */ 211 AccessControlContext(ProtectionDomain caller, DomainCombiner combiner, 212 AccessControlContext parent, AccessControlContext context, 213 Permission[] perms) 214 { 215 /* 216 * Combine the domains from the doPrivileged() context into our 217 * wrapper context, if necessary. 218 */ 219 ProtectionDomain[] callerPDs = null; 220 if (caller != null) { 221 callerPDs = new ProtectionDomain[] { caller }; 222 } 223 if (context != null) { 224 if (combiner != null) { 225 this.context = combiner.combine(callerPDs, context.context); 226 } else { 227 this.context = combine(callerPDs, context.context); 228 } 229 } else { 230 /* 231 * Call combiner even if there is seemingly nothing to combine. 232 */ 233 if (combiner != null) { 234 this.context = combiner.combine(callerPDs, null); 235 } else { 236 this.context = combine(callerPDs, null); 237 } 238 } 239 this.combiner = combiner; 240 241 Permission[] tmp = null; 242 if (perms != null) { 243 tmp = new Permission[perms.length]; 244 for (int i=0; i < perms.length; i++) { 245 if (perms[i] == null) { 246 throw new NullPointerException("permission can't be null"); 247 } 248 249 /* 250 * An AllPermission argument is equivalent to calling 251 * doPrivileged() without any limit permissions. 252 */ 253 if (perms[i].getClass() == AllPermission.class) { 254 parent = null; 255 } 256 tmp[i] = perms[i]; 257 } 258 } 259 260 /* 261 * For a doPrivileged() with limited privilege scope, initialize 262 * the relevant fields. 263 * 264 * The limitedContext field contains the union of all domains which 265 * are enclosed by this limited privilege scope. In other words, 266 * it contains all of the domains which could potentially be checked 267 * if none of the limiting permissions implied a requested permission. 268 */ 269 if (parent != null) { 270 this.limitedContext = combine(parent.context, parent.limitedContext); 271 this.isLimited = true; 272 this.isWrapped = true; 273 this.permissions = tmp; 274 this.parent = parent; 275 this.privilegedContext = context; // used in checkPermission2() 276 } 277 this.isAuthorized = true; 278 } 279 280 281 /** 282 * package private constructor for AccessController.getContext() 283 */ 284 285 AccessControlContext(ProtectionDomain[] context, 286 boolean isPrivileged) 287 { 288 this.context = context; 289 this.isPrivileged = isPrivileged; 290 this.isAuthorized = true; 291 } 292 293 /** 294 * Constructor for JavaSecurityAccess.doIntersectionPrivilege() 295 */ 296 AccessControlContext(ProtectionDomain[] context, 297 AccessControlContext privilegedContext) 298 { 299 this.context = context; 300 this.privilegedContext = privilegedContext; 301 this.isPrivileged = true; 302 } 303 304 /** 305 * Returns this context's context. 306 */ 307 ProtectionDomain[] getContext() { 308 return context; 309 } 310 311 /** 312 * Returns true if this context is privileged. 313 */ 314 boolean isPrivileged() 315 { 316 return isPrivileged; 317 } 318 319 /** 320 * get the assigned combiner from the privileged or inherited context 321 */ 322 DomainCombiner getAssignedCombiner() { 323 AccessControlContext acc; 324 if (isPrivileged) { 325 acc = privilegedContext; 326 } else { 327 acc = AccessController.getInheritedAccessControlContext(); 328 } 329 if (acc != null) { 330 return acc.combiner; 331 } 332 return null; 333 } 334 335 /** 336 * Get the {@code DomainCombiner} associated with this 337 * {@code AccessControlContext}. 338 * 339 * @return the {@code DomainCombiner} associated with this 340 * {@code AccessControlContext}, or {@code null} 341 * if there is none. 342 * 343 * @exception SecurityException if a security manager is installed and 344 * the caller does not have the "getDomainCombiner" 345 * {@link SecurityPermission} 346 * @since 1.3 347 */ 348 public DomainCombiner getDomainCombiner() { 349 350 SecurityManager sm = System.getSecurityManager(); 351 if (sm != null) { 352 sm.checkPermission(SecurityConstants.GET_COMBINER_PERMISSION); 353 } 354 return getCombiner(); 355 } 356 357 /** 358 * package private for AccessController 359 */ 360 DomainCombiner getCombiner() { 361 return combiner; 362 } 363 364 boolean isAuthorized() { 365 return isAuthorized; 366 } 367 368 /** 369 * Determines whether the access request indicated by the 370 * specified permission should be allowed or denied, based on 371 * the security policy currently in effect, and the context in 372 * this object. The request is allowed only if every ProtectionDomain 373 * in the context implies the permission. Otherwise the request is 374 * denied. 375 * 376 * <p> 377 * This method quietly returns if the access request 378 * is permitted, or throws a suitable AccessControlException otherwise. 379 * 380 * @param perm the requested permission. 381 * 382 * @exception AccessControlException if the specified permission 383 * is not permitted, based on the current security policy and the 384 * context encapsulated by this object. 385 * @exception NullPointerException if the permission to check for is null. 386 */ 387 public void checkPermission(Permission perm) 388 throws AccessControlException 389 { 390 boolean dumpDebug = false; 391 392 if (perm == null) { 393 throw new NullPointerException("permission can't be null"); 394 } 395 if (getDebug() != null) { 396 // If "codebase" is not specified, we dump the info by default. 397 dumpDebug = !Debug.isOn("codebase="); 398 if (!dumpDebug) { 399 // If "codebase" is specified, only dump if the specified code 400 // value is in the stack. 401 for (int i = 0; context != null && i < context.length; i++) { 402 if (context[i].getCodeSource() != null && 403 context[i].getCodeSource().getLocation() != null && 404 Debug.isOn("codebase=" + context[i].getCodeSource().getLocation().toString())) { 405 dumpDebug = true; 406 break; 407 } 408 } 409 } 410 411 dumpDebug &= !Debug.isOn("permission=") || 412 Debug.isOn("permission=" + perm.getClass().getCanonicalName()); 413 414 if (dumpDebug && Debug.isOn("stack")) { 415 Thread.dumpStack(); 416 } 417 418 if (dumpDebug && Debug.isOn("domain")) { 419 if (context == null) { 420 debug.println("domain (context is null)"); 421 } else { 422 for (int i=0; i< context.length; i++) { 423 debug.println("domain "+i+" "+context[i]); 424 } 425 } 426 } 427 } 428 429 /* 430 * iterate through the ProtectionDomains in the context. 431 * Stop at the first one that doesn't allow the 432 * requested permission (throwing an exception). 433 * 434 */ 435 436 /* if ctxt is null, all we had on the stack were system domains, 437 or the first domain was a Privileged system domain. This 438 is to make the common case for system code very fast */ 439 440 if (context == null) { 441 checkPermission2(perm); 442 return; 443 } 444 445 for (int i=0; i< context.length; i++) { 446 if (context[i] != null && !context[i].implies(perm)) { 447 if (dumpDebug) { 448 debug.println("access denied " + perm); 449 } 450 451 if (Debug.isOn("failure") && debug != null) { 452 // Want to make sure this is always displayed for failure, 453 // but do not want to display again if already displayed 454 // above. 455 if (!dumpDebug) { 456 debug.println("access denied " + perm); 457 } 458 Thread.dumpStack(); 459 final ProtectionDomain pd = context[i]; 460 final Debug db = debug; 461 AccessController.doPrivileged (new PrivilegedAction<>() { 462 public Void run() { 463 db.println("domain that failed "+pd); 464 return null; 465 } 466 }); 467 } 468 throw new AccessControlException("access denied "+perm, perm); 469 } 470 } 471 472 // allow if all of them allowed access 473 if (dumpDebug) { 474 debug.println("access allowed "+perm); 475 } 476 477 checkPermission2(perm); 478 } 479 480 /* 481 * Check the domains associated with the limited privilege scope. 482 */ 483 private void checkPermission2(Permission perm) { 484 if (!isLimited) { 485 return; 486 } 487 488 /* 489 * Check the doPrivileged() context parameter, if present. 490 */ 491 if (privilegedContext != null) { 492 privilegedContext.checkPermission2(perm); 493 } 494 495 /* 496 * Ignore the limited permissions and parent fields of a wrapper 497 * context since they were already carried down into the unwrapped 498 * context. 499 */ 500 if (isWrapped) { 501 return; 502 } 503 504 /* 505 * Try to match any limited privilege scope. 506 */ 507 if (permissions != null) { 508 Class<?> permClass = perm.getClass(); 509 for (int i=0; i < permissions.length; i++) { 510 Permission limit = permissions[i]; 511 if (limit.getClass().equals(permClass) && limit.implies(perm)) { 512 return; 513 } 514 } 515 } 516 517 /* 518 * Check the limited privilege scope up the call stack or the inherited 519 * parent thread call stack of this ACC. 520 */ 521 if (parent != null) { 522 /* 523 * As an optimization, if the parent context is the inherited call 524 * stack context from a parent thread then checking the protection 525 * domains of the parent context is redundant since they have 526 * already been merged into the child thread's context by 527 * optimize(). When parent is set to an inherited context this 528 * context was not directly created by a limited scope 529 * doPrivileged() and it does not have its own limited permissions. 530 */ 531 if (permissions == null) { 532 parent.checkPermission2(perm); 533 } else { 534 parent.checkPermission(perm); 535 } 536 } 537 } 538 539 /** 540 * Take the stack-based context (this) and combine it with the 541 * privileged or inherited context, if need be. Any limited 542 * privilege scope is flagged regardless of whether the assigned 543 * context comes from an immediately enclosing limited doPrivileged(). 544 * The limited privilege scope can indirectly flow from the inherited 545 * parent thread or an assigned context previously captured by getContext(). 546 */ 547 AccessControlContext optimize() { 548 // the assigned (privileged or inherited) context 549 AccessControlContext acc; 550 DomainCombiner combiner = null; 551 AccessControlContext parent = null; 552 Permission[] permissions = null; 553 554 if (isPrivileged) { 555 acc = privilegedContext; 556 if (acc != null) { 557 /* 558 * If the context is from a limited scope doPrivileged() then 559 * copy the permissions and parent fields out of the wrapper 560 * context that was created to hold them. 561 */ 562 if (acc.isWrapped) { 563 permissions = acc.permissions; 564 parent = acc.parent; 565 } 566 } 567 } else { 568 acc = AccessController.getInheritedAccessControlContext(); 569 if (acc != null) { 570 /* 571 * If the inherited context is constrained by a limited scope 572 * doPrivileged() then set it as our parent so we will process 573 * the non-domain-related state. 574 */ 575 if (acc.isLimited) { 576 parent = acc; 577 } 578 } 579 } 580 581 // this.context could be null if only system code is on the stack; 582 // in that case, ignore the stack context 583 boolean skipStack = (context == null); 584 585 // acc.context could be null if only system code was involved; 586 // in that case, ignore the assigned context 587 boolean skipAssigned = (acc == null || acc.context == null); 588 ProtectionDomain[] assigned = (skipAssigned) ? null : acc.context; 589 ProtectionDomain[] pd; 590 591 // if there is no enclosing limited privilege scope on the stack or 592 // inherited from a parent thread 593 boolean skipLimited = ((acc == null || !acc.isWrapped) && parent == null); 594 595 if (acc != null && acc.combiner != null) { 596 // let the assigned acc's combiner do its thing 597 if (getDebug() != null) { 598 debug.println("AccessControlContext invoking the Combiner"); 599 } 600 601 // No need to clone current and assigned.context 602 // combine() will not update them 603 combiner = acc.combiner; 604 pd = combiner.combine(context, assigned); 605 } else { 606 if (skipStack) { 607 if (skipAssigned) { 608 calculateFields(acc, parent, permissions); 609 return this; 610 } else if (skipLimited) { 611 return acc; 612 } 613 } else if (assigned != null) { 614 if (skipLimited) { 615 // optimization: if there is a single stack domain and 616 // that domain is already in the assigned context; no 617 // need to combine 618 if (context.length == 1 && context[0] == assigned[0]) { 619 return acc; 620 } 621 } 622 } 623 624 pd = combine(context, assigned); 625 if (skipLimited && !skipAssigned && pd == assigned) { 626 return acc; 627 } else if (skipAssigned && pd == context) { 628 calculateFields(acc, parent, permissions); 629 return this; 630 } 631 } 632 633 // Reuse existing ACC 634 this.context = pd; 635 this.combiner = combiner; 636 this.isPrivileged = false; 637 638 calculateFields(acc, parent, permissions); 639 return this; 640 } 641 642 643 /* 644 * Combine the current (stack) and assigned domains. 645 */ 646 private static ProtectionDomain[] combine(ProtectionDomain[] current, 647 ProtectionDomain[] assigned) { 648 649 // current could be null if only system code is on the stack; 650 // in that case, ignore the stack context 651 boolean skipStack = (current == null); 652 653 // assigned could be null if only system code was involved; 654 // in that case, ignore the assigned context 655 boolean skipAssigned = (assigned == null); 656 657 int slen = (skipStack) ? 0 : current.length; 658 659 // optimization: if there is no assigned context and the stack length 660 // is less then or equal to two; there is no reason to compress the 661 // stack context, it already is 662 if (skipAssigned && slen <= 2) { 663 return current; 664 } 665 666 int n = (skipAssigned) ? 0 : assigned.length; 667 668 // now we combine both of them, and create a new context 669 ProtectionDomain[] pd = new ProtectionDomain[slen + n]; 670 671 // first copy in the assigned context domains, no need to compress 672 if (!skipAssigned) { 673 System.arraycopy(assigned, 0, pd, 0, n); 674 } 675 676 // now add the stack context domains, discarding nulls and duplicates 677 outer: 678 for (int i = 0; i < slen; i++) { 679 ProtectionDomain sd = current[i]; 680 if (sd != null) { 681 for (int j = 0; j < n; j++) { 682 if (sd == pd[j]) { 683 continue outer; 684 } 685 } 686 pd[n++] = sd; 687 } 688 } 689 690 // if length isn't equal, we need to shorten the array 691 if (n != pd.length) { 692 // optimization: if we didn't really combine anything 693 if (!skipAssigned && n == assigned.length) { 694 return assigned; 695 } else if (skipAssigned && n == slen) { 696 return current; 697 } 698 ProtectionDomain[] tmp = new ProtectionDomain[n]; 699 System.arraycopy(pd, 0, tmp, 0, n); 700 pd = tmp; 701 } 702 703 return pd; 704 } 705 706 707 /* 708 * Calculate the additional domains that could potentially be reached via 709 * limited privilege scope. Mark the context as being subject to limited 710 * privilege scope unless the reachable domains (if any) are already 711 * contained in this domain context (in which case any limited 712 * privilege scope checking would be redundant). 713 */ 714 private void calculateFields(AccessControlContext assigned, 715 AccessControlContext parent, Permission[] permissions) 716 { 717 ProtectionDomain[] parentLimit = null; 718 ProtectionDomain[] assignedLimit = null; 719 ProtectionDomain[] newLimit; 720 721 parentLimit = (parent != null)? parent.limitedContext: null; 722 assignedLimit = (assigned != null)? assigned.limitedContext: null; 723 newLimit = combine(parentLimit, assignedLimit); 724 if (newLimit != null) { 725 if (context == null || !containsAllPDs(newLimit, context)) { 726 this.limitedContext = newLimit; 727 this.permissions = permissions; 728 this.parent = parent; 729 this.isLimited = true; 730 } 731 } 732 } 733 734 735 /** 736 * Checks two AccessControlContext objects for equality. 737 * Checks that {@code obj} is 738 * an AccessControlContext and has the same set of ProtectionDomains 739 * as this context. 740 * 741 * @param obj the object we are testing for equality with this object. 742 * @return true if {@code obj} is an AccessControlContext, and has the 743 * same set of ProtectionDomains as this context, false otherwise. 744 */ 745 public boolean equals(Object obj) { 746 if (obj == this) 747 return true; 748 749 if (! (obj instanceof AccessControlContext)) 750 return false; 751 752 AccessControlContext that = (AccessControlContext) obj; 753 754 if (!equalContext(that)) 755 return false; 756 757 if (!equalLimitedContext(that)) 758 return false; 759 760 return true; 761 } 762 763 /* 764 * Compare for equality based on state that is free of limited 765 * privilege complications. 766 */ 767 private boolean equalContext(AccessControlContext that) { 768 if (!equalPDs(this.context, that.context)) 769 return false; 770 771 if (this.combiner == null && that.combiner != null) 772 return false; 773 774 if (this.combiner != null && !this.combiner.equals(that.combiner)) 775 return false; 776 777 return true; 778 } 779 780 private boolean equalPDs(ProtectionDomain[] a, ProtectionDomain[] b) { 781 if (a == null) { 782 return (b == null); 783 } 784 785 if (b == null) 786 return false; 787 788 if (!(containsAllPDs(a, b) && containsAllPDs(b, a))) 789 return false; 790 791 return true; 792 } 793 794 /* 795 * Compare for equality based on state that is captured during a 796 * call to AccessController.getContext() when a limited privilege 797 * scope is in effect. 798 */ 799 private boolean equalLimitedContext(AccessControlContext that) { 800 if (that == null) 801 return false; 802 803 /* 804 * If neither instance has limited privilege scope then we're done. 805 */ 806 if (!this.isLimited && !that.isLimited) 807 return true; 808 809 /* 810 * If only one instance has limited privilege scope then we're done. 811 */ 812 if (!(this.isLimited && that.isLimited)) 813 return false; 814 815 /* 816 * Wrapped instances should never escape outside the implementation 817 * this class and AccessController so this will probably never happen 818 * but it only makes any sense to compare if they both have the same 819 * isWrapped state. 820 */ 821 if ((this.isWrapped && !that.isWrapped) || 822 (!this.isWrapped && that.isWrapped)) { 823 return false; 824 } 825 826 if (this.permissions == null && that.permissions != null) 827 return false; 828 829 if (this.permissions != null && that.permissions == null) 830 return false; 831 832 if (!(this.containsAllLimits(that) && that.containsAllLimits(this))) 833 return false; 834 835 /* 836 * Skip through any wrapped contexts. 837 */ 838 AccessControlContext thisNextPC = getNextPC(this); 839 AccessControlContext thatNextPC = getNextPC(that); 840 841 /* 842 * The protection domains and combiner of a privilegedContext are 843 * not relevant because they have already been included in the context 844 * of this instance by optimize() so we only care about any limited 845 * privilege state they may have. 846 */ 847 if (thisNextPC == null && thatNextPC != null && thatNextPC.isLimited) 848 return false; 849 850 if (thisNextPC != null && !thisNextPC.equalLimitedContext(thatNextPC)) 851 return false; 852 853 if (this.parent == null && that.parent != null) 854 return false; 855 856 if (this.parent != null && !this.parent.equals(that.parent)) 857 return false; 858 859 return true; 860 } 861 862 /* 863 * Follow the privilegedContext link making our best effort to skip 864 * through any wrapper contexts. 865 */ 866 private static AccessControlContext getNextPC(AccessControlContext acc) { 867 while (acc != null && acc.privilegedContext != null) { 868 acc = acc.privilegedContext; 869 if (!acc.isWrapped) 870 return acc; 871 } 872 return null; 873 } 874 875 private static boolean containsAllPDs(ProtectionDomain[] thisContext, 876 ProtectionDomain[] thatContext) { 877 boolean match = false; 878 879 // 880 // ProtectionDomains within an ACC currently cannot be null 881 // and this is enforced by the constructor and the various 882 // optimize methods. However, historically this logic made attempts 883 // to support the notion of a null PD and therefore this logic continues 884 // to support that notion. 885 ProtectionDomain thisPd; 886 for (int i = 0; i < thisContext.length; i++) { 887 match = false; 888 if ((thisPd = thisContext[i]) == null) { 889 for (int j = 0; (j < thatContext.length) && !match; j++) { 890 match = (thatContext[j] == null); 891 } 892 } else { 893 Class<?> thisPdClass = thisPd.getClass(); 894 ProtectionDomain thatPd; 895 for (int j = 0; (j < thatContext.length) && !match; j++) { 896 thatPd = thatContext[j]; 897 898 // Class check required to avoid PD exposure (4285406) 899 match = (thatPd != null && 900 thisPdClass == thatPd.getClass() && thisPd.equals(thatPd)); 901 } 902 } 903 if (!match) return false; 904 } 905 return match; 906 } 907 908 private boolean containsAllLimits(AccessControlContext that) { 909 boolean match = false; 910 Permission thisPerm; 911 912 if (this.permissions == null && that.permissions == null) 913 return true; 914 915 for (int i = 0; i < this.permissions.length; i++) { 916 Permission limit = this.permissions[i]; 917 Class <?> limitClass = limit.getClass(); 918 match = false; 919 for (int j = 0; (j < that.permissions.length) && !match; j++) { 920 Permission perm = that.permissions[j]; 921 match = (limitClass.equals(perm.getClass()) && 922 limit.equals(perm)); 923 } 924 if (!match) return false; 925 } 926 return match; 927 } 928 929 930 /** 931 * Returns the hash code value for this context. The hash code 932 * is computed by exclusive or-ing the hash code of all the protection 933 * domains in the context together. 934 * 935 * @return a hash code value for this context. 936 */ 937 938 public int hashCode() { 939 int hashCode = 0; 940 941 if (context == null) 942 return hashCode; 943 944 for (int i =0; i < context.length; i++) { 945 if (context[i] != null) 946 hashCode ^= context[i].hashCode(); 947 } 948 949 return hashCode; 950 } 951 }