1 /* 2 * Copyright (c) 1997, 2019, 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 sun.security.provider; 27 28 import java.io.*; 29 import java.lang.reflect.*; 30 import java.net.MalformedURLException; 31 import java.net.URL; 32 import java.net.URI; 33 import java.nio.file.Files; 34 import java.nio.file.Path; 35 import java.util.*; 36 import java.security.*; 37 import java.security.cert.Certificate; 38 import java.security.cert.X509Certificate; 39 import javax.security.auth.Subject; 40 import javax.security.auth.x500.X500Principal; 41 import java.net.SocketPermission; 42 import java.net.NetPermission; 43 import java.util.concurrent.ConcurrentHashMap; 44 import jdk.internal.access.JavaSecurityAccess; 45 import jdk.internal.access.SharedSecrets; 46 import jdk.internal.util.StaticProperty; 47 import sun.security.util.*; 48 import sun.net.www.ParseUtil; 49 50 import static java.nio.charset.StandardCharsets.UTF_8; 51 import static jdk.internal.access.JavaSecurityAccess.ProtectionDomainCache; 52 53 /** 54 * This class represents a default Policy implementation for the 55 * "JavaPolicy" type. 56 * 57 * <p> This object stores the policy for the entire Java runtime, 58 * and is the amalgamation of multiple static policy 59 * configurations that resides in files. 60 * The algorithm for locating the policy file(s) and reading their 61 * information into this <code>Policy</code> object is: 62 * 63 * <ol> 64 * <li> 65 * Read in and load the default policy file named 66 * <JAVA_HOME>/lib/security/default.policy. <JAVA_HOME> refers 67 * to the value of the java.home system property, and specifies the directory 68 * where the JRE is installed. This policy file grants permissions to the 69 * modules loaded by the platform class loader. If the default policy file 70 * cannot be loaded, a fatal InternalError is thrown as these permissions 71 * are needed in order for the runtime to operate correctly. 72 * <li> 73 * Loop through the <code>java.security.Security</code> properties, 74 * and <i>policy.url.1</i>, <i>policy.url.2</i>, ..., 75 * <i>policy.url.X</i>". These properties are set 76 * in the Java security properties file, which is located in the file named 77 * <JAVA_HOME>/conf/security/java.security. 78 * Each property value specifies a <code>URL</code> pointing to a 79 * policy file to be loaded. Read in and load each policy. 80 * 81 * If none of these could be loaded, use a builtin static policy 82 * equivalent to the conf/security/java.policy file. 83 * 84 * <li> 85 * The <code>java.lang.System</code> property <i>java.security.policy</i> 86 * may also be set to a <code>URL</code> pointing to another policy file 87 * (which is the case when a user uses the -D switch at runtime). 88 * If this property is defined, and its use is allowed by the 89 * security property file (the Security property, 90 * <i>policy.allowSystemProperty</i> is set to <i>true</i>), 91 * also load that policy. 92 * 93 * If the <i>java.security.policy</i> property is defined using 94 * "==" (rather than "="), then load the specified policy file and ignore 95 * all other configured policies. Note, that the default.policy file is 96 * also loaded, as specified in the first step of the algorithm above. 97 * If the specified policy file cannot be loaded, use a builtin static policy 98 * equivalent to the default conf/security/java.policy file. 99 * </ol> 100 * 101 * Each policy file consists of one or more grant entries, each of 102 * which consists of a number of permission entries. 103 * 104 * <pre> 105 * grant signedBy "<b>alias</b>", codeBase "<b>URL</b>", 106 * principal <b>principalClass</b> "<b>principalName</b>", 107 * principal <b>principalClass</b> "<b>principalName</b>", 108 * ... { 109 * 110 * permission <b>Type</b> "<b>name</b> "<b>action</b>", 111 * signedBy "<b>alias</b>"; 112 * permission <b>Type</b> "<b>name</b> "<b>action</b>", 113 * signedBy "<b>alias</b>"; 114 * .... 115 * }; 116 * </pre> 117 * 118 * All non-bold items above must appear as is (although case 119 * doesn't matter and some are optional, as noted below). 120 * principal entries are optional and need not be present. 121 * Italicized items represent variable values. 122 * 123 * <p> A grant entry must begin with the word <code>grant</code>. 124 * The <code>signedBy</code>,<code>codeBase</code> and <code>principal</code> 125 * name/value pairs are optional. 126 * If they are not present, then any signer (including unsigned code) 127 * will match, and any codeBase will match. 128 * Note that the <i>principalClass</i> 129 * may be set to the wildcard value, *, which allows it to match 130 * any <code>Principal</code> class. In addition, the <i>principalName</i> 131 * may also be set to the wildcard value, *, allowing it to match 132 * any <code>Principal</code> name. When setting the <i>principalName</i> 133 * to the *, do not surround the * with quotes. 134 * 135 * <p> A permission entry must begin with the word <code>permission</code>. 136 * The word <code><i>Type</i></code> in the template above is 137 * a specific permission type, such as <code>java.io.FilePermission</code> 138 * or <code>java.lang.RuntimePermission</code>. 139 * 140 * <p> The "<i>action</i>" is required for 141 * many permission types, such as <code>java.io.FilePermission</code> 142 * (where it specifies what type of file access that is permitted). 143 * It is not required for categories such as 144 * <code>java.lang.RuntimePermission</code> 145 * where it is not necessary - you either have the 146 * permission specified by the <code>"<i>name</i>"</code> 147 * value following the type name or you don't. 148 * 149 * <p> The <code>signedBy</code> name/value pair for a permission entry 150 * is optional. If present, it indicates a signed permission. That is, 151 * the permission class itself must be signed by the given alias in 152 * order for it to be granted. For example, 153 * suppose you have the following grant entry: 154 * 155 * <pre> 156 * grant principal foo.com.Principal "Duke" { 157 * permission Foo "foobar", signedBy "FooSoft"; 158 * } 159 * </pre> 160 * 161 * <p> Then this permission of type <i>Foo</i> is granted if the 162 * <code>Foo.class</code> permission has been signed by the 163 * "FooSoft" alias, or if XXX <code>Foo.class</code> is a 164 * system class (i.e., is found on the CLASSPATH). 165 * 166 * <p> Items that appear in an entry must appear in the specified order 167 * (<code>permission</code>, <i>Type</i>, "<i>name</i>", and 168 * "<i>action</i>"). An entry is terminated with a semicolon. 169 * 170 * <p> Case is unimportant for the identifiers (<code>permission</code>, 171 * <code>signedBy</code>, <code>codeBase</code>, etc.) but is 172 * significant for the <i>Type</i> 173 * or for any string that is passed in as a value. 174 * 175 * <p> An example of two entries in a policy configuration file is 176 * <pre> 177 * // if the code is comes from "foo.com" and is running as "Duke", 178 * // grant it read/write to all files in /tmp. 179 * 180 * grant codeBase "foo.com", principal foo.com.Principal "Duke" { 181 * permission java.io.FilePermission "/tmp/*", "read,write"; 182 * }; 183 * 184 * // grant any code running as "Duke" permission to read 185 * // the "java.vendor" Property. 186 * 187 * grant principal foo.com.Principal "Duke" { 188 * permission java.util.PropertyPermission "java.vendor"; 189 * 190 * 191 * </pre> 192 * This Policy implementation supports special handling of any 193 * permission that contains the string, "<b>${{self}}</b>", as part of 194 * its target name. When such a permission is evaluated 195 * (such as during a security check), <b>${{self}}</b> is replaced 196 * with one or more Principal class/name pairs. The exact 197 * replacement performed depends upon the contents of the 198 * grant clause to which the permission belongs. 199 * <p> 200 * 201 * If the grant clause does not contain any principal information, 202 * the permission will be ignored (permissions containing 203 * <b>${{self}}</b> in their target names are only valid in the context 204 * of a principal-based grant clause). For example, BarPermission 205 * will always be ignored in the following grant clause: 206 * 207 * <pre> 208 * grant codebase "www.foo.com", signedby "duke" { 209 * permission BarPermission "... ${{self}} ..."; 210 * }; 211 * </pre> 212 * 213 * If the grant clause contains principal information, <b>${{self}}</b> 214 * will be replaced with that same principal information. 215 * For example, <b>${{self}}</b> in BarPermission will be replaced by 216 * <b>javax.security.auth.x500.X500Principal "cn=Duke"</b> 217 * in the following grant clause: 218 * 219 * <pre> 220 * grant principal javax.security.auth.x500.X500Principal "cn=Duke" { 221 * permission BarPermission "... ${{self}} ..."; 222 * }; 223 * </pre> 224 * 225 * If there is a comma-separated list of principals in the grant 226 * clause, then <b>${{self}}</b> will be replaced by the same 227 * comma-separated list or principals. 228 * In the case where both the principal class and name are 229 * wildcarded in the grant clause, <b>${{self}}</b> is replaced 230 * with all the principals associated with the <code>Subject</code> 231 * in the current <code>AccessControlContext</code>. 232 * 233 * <p> For PrivateCredentialPermissions, you can also use "<b>self</b>" 234 * instead of "<b>${{self}}</b>". However the use of "<b>self</b>" is 235 * deprecated in favour of "<b>${{self}}</b>". 236 * 237 * @see java.security.CodeSource 238 * @see java.security.Permissions 239 * @see java.security.ProtectionDomain 240 */ 241 public class PolicyFile extends java.security.Policy { 242 243 private static final Debug debug = Debug.getInstance("policy"); 244 245 private static final String SELF = "${{self}}"; 246 private static final String X500PRINCIPAL = 247 "javax.security.auth.x500.X500Principal"; 248 private static final String POLICY = "java.security.policy"; 249 private static final String POLICY_URL = "policy.url."; 250 251 private static final int DEFAULT_CACHE_SIZE = 1; 252 253 // contains the policy grant entries, PD cache, and alias mapping 254 // can be updated if refresh() is called 255 private volatile PolicyInfo policyInfo; 256 257 private boolean expandProperties = true; 258 private boolean allowSystemProperties = true; 259 private boolean notUtf8 = false; 260 private URL url; 261 262 // for use with the reflection API 263 private static final Class<?>[] PARAMS0 = { }; 264 private static final Class<?>[] PARAMS1 = { String.class }; 265 private static final Class<?>[] PARAMS2 = { String.class, String.class }; 266 267 /** 268 * When a policy file has a syntax error, the exception code may generate 269 * another permission check and this can cause the policy file to be parsed 270 * repeatedly, leading to a StackOverflowError or ClassCircularityError. 271 * To avoid this, this set is populated with policy files that have been 272 * previously parsed and have syntax errors, so that they can be 273 * subsequently ignored. 274 */ 275 private static Set<URL> badPolicyURLs = 276 Collections.newSetFromMap(new ConcurrentHashMap<URL,Boolean>()); 277 278 /** 279 * Initializes the Policy object and reads the default policy 280 * configuration file(s) into the Policy object. 281 */ 282 public PolicyFile() { 283 init((URL)null); 284 } 285 286 /** 287 * Initializes the Policy object and reads the default policy 288 * from the specified URL only. 289 */ 290 public PolicyFile(URL url) { 291 this.url = url; 292 init(url); 293 } 294 295 /** 296 * Initializes the Policy object and reads the default policy 297 * configuration file(s) into the Policy object. 298 * 299 * See the class description for details on the algorithm used to 300 * initialize the Policy object. 301 */ 302 private void init(URL url) { 303 // Properties are set once for each init(); ignore changes between 304 // between diff invocations of initPolicyFile(policy, url, info). 305 String numCacheStr = 306 AccessController.doPrivileged(new PrivilegedAction<>() { 307 @Override 308 public String run() { 309 expandProperties = "true".equalsIgnoreCase 310 (Security.getProperty("policy.expandProperties")); 311 allowSystemProperties = "true".equalsIgnoreCase 312 (Security.getProperty("policy.allowSystemProperty")); 313 notUtf8 = "false".equalsIgnoreCase 314 (System.getProperty("sun.security.policy.utf8")); 315 return System.getProperty("sun.security.policy.numcaches"); 316 }}); 317 318 int numCaches; 319 if (numCacheStr != null) { 320 try { 321 numCaches = Integer.parseInt(numCacheStr); 322 } catch (NumberFormatException e) { 323 numCaches = DEFAULT_CACHE_SIZE; 324 } 325 } else { 326 numCaches = DEFAULT_CACHE_SIZE; 327 } 328 // System.out.println("number caches=" + numCaches); 329 PolicyInfo newInfo = new PolicyInfo(numCaches); 330 initPolicyFile(newInfo, url); 331 policyInfo = newInfo; 332 } 333 334 private void initPolicyFile(final PolicyInfo newInfo, final URL url) { 335 336 // always load default.policy 337 AccessController.doPrivileged(new PrivilegedAction<>() { 338 @Override 339 public Void run() { 340 initDefaultPolicy(newInfo); 341 return null; 342 } 343 }); 344 345 if (url != null) { 346 347 /** 348 * If the caller specified a URL via Policy.getInstance, 349 * we only read from default.policy and that URL. 350 */ 351 352 if (debug != null) { 353 debug.println("reading " + url); 354 } 355 AccessController.doPrivileged(new PrivilegedAction<>() { 356 @Override 357 public Void run() { 358 if (init(url, newInfo) == false) { 359 // use static policy if all else fails 360 initStaticPolicy(newInfo); 361 } 362 return null; 363 } 364 }); 365 366 } else { 367 368 /** 369 * Caller did not specify URL via Policy.getInstance. 370 * Read from URLs listed in the java.security properties file. 371 */ 372 373 boolean loaded_one = initPolicyFile(POLICY, POLICY_URL, newInfo); 374 // To maintain strict backward compatibility 375 // we load the static policy only if POLICY load failed 376 if (!loaded_one) { 377 // use static policy if all else fails 378 initStaticPolicy(newInfo); 379 } 380 } 381 } 382 383 private boolean initPolicyFile(final String propname, final String urlname, 384 final PolicyInfo newInfo) { 385 boolean loadedPolicy = 386 AccessController.doPrivileged(new PrivilegedAction<>() { 387 @Override 388 public Boolean run() { 389 boolean loaded_policy = false; 390 391 if (allowSystemProperties) { 392 String extra_policy = System.getProperty(propname); 393 if (extra_policy != null) { 394 boolean overrideAll = false; 395 if (extra_policy.startsWith("=")) { 396 overrideAll = true; 397 extra_policy = extra_policy.substring(1); 398 } 399 try { 400 extra_policy = 401 PropertyExpander.expand(extra_policy); 402 URL policyURL; 403 404 File policyFile = new File(extra_policy); 405 if (policyFile.exists()) { 406 policyURL = ParseUtil.fileToEncodedURL 407 (new File(policyFile.getCanonicalPath())); 408 } else { 409 policyURL = new URL(extra_policy); 410 } 411 if (debug != null) { 412 debug.println("reading "+policyURL); 413 } 414 if (init(policyURL, newInfo)) { 415 loaded_policy = true; 416 } 417 } catch (Exception e) { 418 // ignore. 419 if (debug != null) { 420 debug.println("caught exception: "+e); 421 } 422 } 423 if (overrideAll) { 424 if (debug != null) { 425 debug.println("overriding other policies!"); 426 } 427 return Boolean.valueOf(loaded_policy); 428 } 429 } 430 } 431 432 int n = 1; 433 String policy_uri; 434 435 while ((policy_uri = Security.getProperty(urlname+n)) != null) { 436 try { 437 URL policy_url = null; 438 String expanded_uri = PropertyExpander.expand 439 (policy_uri).replace(File.separatorChar, '/'); 440 441 if (policy_uri.startsWith("file:${java.home}/") || 442 policy_uri.startsWith("file:${user.home}/")) { 443 444 // this special case accommodates 445 // the situation java.home/user.home 446 // expand to a single slash, resulting in 447 // a file://foo URI 448 policy_url = new File 449 (expanded_uri.substring(5)).toURI().toURL(); 450 } else { 451 policy_url = new URI(expanded_uri).toURL(); 452 } 453 454 if (debug != null) { 455 debug.println("reading " + policy_url); 456 } 457 if (init(policy_url, newInfo)) { 458 loaded_policy = true; 459 } 460 } catch (Exception e) { 461 if (debug != null) { 462 debug.println( 463 "Debug info only. Error reading policy " +e); 464 e.printStackTrace(); 465 } 466 // ignore that policy 467 } 468 n++; 469 } 470 return Boolean.valueOf(loaded_policy); 471 } 472 }); 473 474 return loadedPolicy; 475 } 476 477 private void initDefaultPolicy(PolicyInfo newInfo) { 478 Path defaultPolicy = Path.of(StaticProperty.javaHome(), 479 "lib", 480 "security", 481 "default.policy"); 482 if (debug != null) { 483 debug.println("reading " + defaultPolicy); 484 } 485 try (BufferedReader br = Files.newBufferedReader(defaultPolicy)) { 486 487 PolicyParser pp = new PolicyParser(expandProperties); 488 pp.read(br); 489 490 Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements(); 491 while (enum_.hasMoreElements()) { 492 PolicyParser.GrantEntry ge = enum_.nextElement(); 493 addGrantEntry(ge, null, newInfo); 494 } 495 } catch (Exception e) { 496 throw new InternalError("Failed to load default.policy", e); 497 } 498 } 499 500 /** 501 * Reads a policy configuration into the Policy object using a 502 * Reader object. 503 */ 504 private boolean init(URL policy, PolicyInfo newInfo) { 505 506 // skip parsing policy file if it has been previously parsed and 507 // has syntax errors 508 if (badPolicyURLs.contains(policy)) { 509 if (debug != null) { 510 debug.println("skipping bad policy file: " + policy); 511 } 512 return false; 513 } 514 515 try (InputStreamReader isr = 516 getInputStreamReader(PolicyUtil.getInputStream(policy))) { 517 518 PolicyParser pp = new PolicyParser(expandProperties); 519 pp.read(isr); 520 521 KeyStore keyStore = null; 522 try { 523 keyStore = PolicyUtil.getKeyStore 524 (policy, 525 pp.getKeyStoreUrl(), 526 pp.getKeyStoreType(), 527 pp.getKeyStoreProvider(), 528 pp.getStorePassURL(), 529 debug); 530 } catch (Exception e) { 531 // ignore, treat it like we have no keystore 532 if (debug != null) { 533 debug.println("Debug info only. Ignoring exception."); 534 e.printStackTrace(); 535 } 536 } 537 538 Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements(); 539 while (enum_.hasMoreElements()) { 540 PolicyParser.GrantEntry ge = enum_.nextElement(); 541 addGrantEntry(ge, keyStore, newInfo); 542 } 543 return true; 544 } catch (PolicyParser.ParsingException pe) { 545 // record bad policy file to avoid later reparsing it 546 badPolicyURLs.add(policy); 547 Object[] source = {policy, pe.getNonlocalizedMessage()}; 548 System.err.println(LocalizedMessage.getNonlocalized 549 (POLICY + ".error.parsing.policy.message", source)); 550 if (debug != null) { 551 pe.printStackTrace(); 552 } 553 } catch (Exception e) { 554 if (debug != null) { 555 debug.println("error parsing "+policy); 556 debug.println(e.toString()); 557 e.printStackTrace(); 558 } 559 } 560 561 return false; 562 } 563 564 private InputStreamReader getInputStreamReader(InputStream is) { 565 /* 566 * Read in policy using UTF-8 by default. 567 * 568 * Check non-standard system property to see if the default encoding 569 * should be used instead. 570 */ 571 return (notUtf8) 572 ? new InputStreamReader(is) 573 : new InputStreamReader(is, UTF_8); 574 } 575 576 private void initStaticPolicy(final PolicyInfo newInfo) { 577 if (debug != null) { 578 debug.println("Initializing with static permissions"); 579 } 580 AccessController.doPrivileged(new PrivilegedAction<>() { 581 @Override 582 public Void run() { 583 PolicyEntry pe = new PolicyEntry(new CodeSource(null, 584 (Certificate[]) null)); 585 pe.add(SecurityConstants.LOCAL_LISTEN_PERMISSION); 586 pe.add(new PropertyPermission("java.version", 587 SecurityConstants.PROPERTY_READ_ACTION)); 588 pe.add(new PropertyPermission("java.vendor", 589 SecurityConstants.PROPERTY_READ_ACTION)); 590 pe.add(new PropertyPermission("java.vendor.url", 591 SecurityConstants.PROPERTY_READ_ACTION)); 592 pe.add(new PropertyPermission("java.class.version", 593 SecurityConstants.PROPERTY_READ_ACTION)); 594 pe.add(new PropertyPermission("os.name", 595 SecurityConstants.PROPERTY_READ_ACTION)); 596 pe.add(new PropertyPermission("os.version", 597 SecurityConstants.PROPERTY_READ_ACTION)); 598 pe.add(new PropertyPermission("os.arch", 599 SecurityConstants.PROPERTY_READ_ACTION)); 600 pe.add(new PropertyPermission("file.separator", 601 SecurityConstants.PROPERTY_READ_ACTION)); 602 pe.add(new PropertyPermission("path.separator", 603 SecurityConstants.PROPERTY_READ_ACTION)); 604 pe.add(new PropertyPermission("line.separator", 605 SecurityConstants.PROPERTY_READ_ACTION)); 606 pe.add(new PropertyPermission 607 ("java.specification.version", 608 SecurityConstants.PROPERTY_READ_ACTION)); 609 pe.add(new PropertyPermission 610 ("java.specification.vendor", 611 SecurityConstants.PROPERTY_READ_ACTION)); 612 pe.add(new PropertyPermission 613 ("java.specification.name", 614 SecurityConstants.PROPERTY_READ_ACTION)); 615 pe.add(new PropertyPermission 616 ("java.vm.specification.version", 617 SecurityConstants.PROPERTY_READ_ACTION)); 618 pe.add(new PropertyPermission 619 ("java.vm.specification.vendor", 620 SecurityConstants.PROPERTY_READ_ACTION)); 621 pe.add(new PropertyPermission 622 ("java.vm.specification.name", 623 SecurityConstants.PROPERTY_READ_ACTION)); 624 pe.add(new PropertyPermission("java.vm.version", 625 SecurityConstants.PROPERTY_READ_ACTION)); 626 pe.add(new PropertyPermission("java.vm.vendor", 627 SecurityConstants.PROPERTY_READ_ACTION)); 628 pe.add(new PropertyPermission("java.vm.name", 629 SecurityConstants.PROPERTY_READ_ACTION)); 630 631 // No need to sync because noone has access to newInfo yet 632 newInfo.policyEntries.add(pe); 633 634 return null; 635 } 636 }); 637 } 638 639 /** 640 * Given a GrantEntry, create a codeSource. 641 * 642 * @return null if signedBy alias is not recognized 643 */ 644 private CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore, 645 PolicyInfo newInfo) throws java.net.MalformedURLException 646 { 647 Certificate[] certs = null; 648 if (ge.signedBy != null) { 649 certs = getCertificates(keyStore, ge.signedBy, newInfo); 650 if (certs == null) { 651 // we don't have a key for this alias, 652 // just return 653 if (debug != null) { 654 debug.println(" -- No certs for alias '" + 655 ge.signedBy + "' - ignoring entry"); 656 } 657 return null; 658 } 659 } 660 661 URL location; 662 663 if (ge.codeBase != null) 664 location = new URL(ge.codeBase); 665 else 666 location = null; 667 668 return (canonicalizeCodebase(new CodeSource(location, certs),false)); 669 } 670 671 /** 672 * Add one policy entry to the list. 673 */ 674 private void addGrantEntry(PolicyParser.GrantEntry ge, 675 KeyStore keyStore, PolicyInfo newInfo) { 676 677 if (debug != null) { 678 debug.println("Adding policy entry: "); 679 debug.println(" signedBy " + ge.signedBy); 680 debug.println(" codeBase " + ge.codeBase); 681 if (ge.principals != null) { 682 for (PolicyParser.PrincipalEntry pppe : ge.principals) { 683 debug.println(" " + pppe.toString()); 684 } 685 } 686 } 687 688 try { 689 CodeSource codesource = getCodeSource(ge, keyStore, newInfo); 690 // skip if signedBy alias was unknown... 691 if (codesource == null) return; 692 693 // perform keystore alias principal replacement. 694 // for example, if alias resolves to X509 certificate, 695 // replace principal with: <X500Principal class> <SubjectDN> 696 // -- skip if alias is unknown 697 if (replacePrincipals(ge.principals, keyStore) == false) 698 return; 699 PolicyEntry entry = new PolicyEntry(codesource, ge.principals); 700 Enumeration<PolicyParser.PermissionEntry> enum_ = 701 ge.permissionElements(); 702 while (enum_.hasMoreElements()) { 703 PolicyParser.PermissionEntry pe = enum_.nextElement(); 704 705 try { 706 // perform ${{ ... }} expansions within permission name 707 expandPermissionName(pe, keyStore); 708 709 // XXX special case PrivateCredentialPermission-SELF 710 Permission perm; 711 if (pe.permission.equals 712 ("javax.security.auth.PrivateCredentialPermission") && 713 pe.name.endsWith(" self")) { 714 pe.name = pe.name.substring(0, pe.name.indexOf("self")) 715 + SELF; 716 } 717 // check for self 718 if (pe.name != null && pe.name.indexOf(SELF) != -1) { 719 // Create a "SelfPermission" , it could be an 720 // an unresolved permission which will be resolved 721 // when implies is called 722 // Add it to entry 723 Certificate[] certs; 724 if (pe.signedBy != null) { 725 certs = getCertificates(keyStore, 726 pe.signedBy, 727 newInfo); 728 } else { 729 certs = null; 730 } 731 perm = new SelfPermission(pe.permission, 732 pe.name, 733 pe.action, 734 certs); 735 } else { 736 perm = getInstance(pe.permission, 737 pe.name, 738 pe.action); 739 } 740 entry.add(perm); 741 if (debug != null) { 742 debug.println(" "+perm); 743 } 744 } catch (ClassNotFoundException cnfe) { 745 Certificate[] certs; 746 if (pe.signedBy != null) { 747 certs = getCertificates(keyStore, 748 pe.signedBy, 749 newInfo); 750 } else { 751 certs = null; 752 } 753 754 // only add if we had no signer or we had 755 // a signer and found the keys for it. 756 if (certs != null || pe.signedBy == null) { 757 Permission perm = new UnresolvedPermission( 758 pe.permission, 759 pe.name, 760 pe.action, 761 certs); 762 entry.add(perm); 763 if (debug != null) { 764 debug.println(" "+perm); 765 } 766 } 767 } catch (java.lang.reflect.InvocationTargetException ite) { 768 Object[] source = {pe.permission, 769 ite.getTargetException().toString()}; 770 System.err.println( 771 LocalizedMessage.getNonlocalized( 772 POLICY + ".error.adding.Permission.perm.message", 773 source)); 774 } catch (Exception e) { 775 Object[] source = {pe.permission, 776 e.toString()}; 777 System.err.println( 778 LocalizedMessage.getNonlocalized( 779 POLICY + ".error.adding.Permission.perm.message", 780 source)); 781 } 782 } 783 784 // No need to sync because noone has access to newInfo yet 785 newInfo.policyEntries.add(entry); 786 } catch (Exception e) { 787 Object[] source = {e.toString()}; 788 System.err.println( 789 LocalizedMessage.getNonlocalized( 790 POLICY + ".error.adding.Entry.message", 791 source)); 792 } 793 if (debug != null) 794 debug.println(); 795 } 796 797 /** 798 * Returns a new Permission object of the given Type. The Permission is 799 * created by getting the 800 * Class object using the <code>Class.forName</code> method, and using 801 * the reflection API to invoke the (String name, String actions) 802 * constructor on the 803 * object. 804 * 805 * @param type the type of Permission being created. 806 * @param name the name of the Permission being created. 807 * @param actions the actions of the Permission being created. 808 * 809 * @exception ClassNotFoundException if the particular Permission 810 * class could not be found. 811 * 812 * @exception IllegalAccessException if the class or initializer is 813 * not accessible. 814 * 815 * @exception InstantiationException if getInstance tries to 816 * instantiate an abstract class or an interface, or if the 817 * instantiation fails for some other reason. 818 * 819 * @exception NoSuchMethodException if the (String, String) constructor 820 * is not found. 821 * 822 * @exception InvocationTargetException if the underlying Permission 823 * constructor throws an exception. 824 * 825 */ 826 827 private static final Permission getInstance(String type, 828 String name, 829 String actions) 830 throws ClassNotFoundException, 831 InstantiationException, 832 IllegalAccessException, 833 NoSuchMethodException, 834 InvocationTargetException 835 { 836 Class<?> pc = Class.forName(type, false, null); 837 Permission answer = getKnownPermission(pc, name, actions); 838 if (answer != null) { 839 return answer; 840 } 841 if (!Permission.class.isAssignableFrom(pc)) { 842 // not the right subtype 843 throw new ClassCastException(type + " is not a Permission"); 844 } 845 846 if (name == null && actions == null) { 847 try { 848 Constructor<?> c = pc.getConstructor(PARAMS0); 849 return (Permission) c.newInstance(new Object[] {}); 850 } catch (NoSuchMethodException ne) { 851 try { 852 Constructor<?> c = pc.getConstructor(PARAMS1); 853 return (Permission) c.newInstance( 854 new Object[] { name}); 855 } catch (NoSuchMethodException ne1 ) { 856 Constructor<?> c = pc.getConstructor(PARAMS2); 857 return (Permission) c.newInstance( 858 new Object[] { name, actions }); 859 } 860 } 861 } else { 862 if (name != null && actions == null) { 863 try { 864 Constructor<?> c = pc.getConstructor(PARAMS1); 865 return (Permission) c.newInstance(new Object[] { name}); 866 } catch (NoSuchMethodException ne) { 867 Constructor<?> c = pc.getConstructor(PARAMS2); 868 return (Permission) c.newInstance( 869 new Object[] { name, actions }); 870 } 871 } else { 872 Constructor<?> c = pc.getConstructor(PARAMS2); 873 return (Permission) c.newInstance( 874 new Object[] { name, actions }); 875 } 876 } 877 } 878 879 /** 880 * Creates one of the well-known permissions in the java.base module 881 * directly instead of via reflection. Keep list short to not penalize 882 * permissions from other modules. 883 */ 884 private static Permission getKnownPermission(Class<?> claz, String name, 885 String actions) { 886 if (claz.equals(FilePermission.class)) { 887 return new FilePermission(name, actions); 888 } else if (claz.equals(SocketPermission.class)) { 889 return new SocketPermission(name, actions); 890 } else if (claz.equals(RuntimePermission.class)) { 891 return new RuntimePermission(name, actions); 892 } else if (claz.equals(PropertyPermission.class)) { 893 return new PropertyPermission(name, actions); 894 } else if (claz.equals(NetPermission.class)) { 895 return new NetPermission(name, actions); 896 } else if (claz.equals(AllPermission.class)) { 897 return SecurityConstants.ALL_PERMISSION; 898 } else if (claz.equals(SecurityPermission.class)) { 899 return new SecurityPermission(name, actions); 900 } else { 901 return null; 902 } 903 } 904 905 /** 906 * Creates one of the well-known principals in the java.base module 907 * directly instead of via reflection. Keep list short to not penalize 908 * principals from other modules. 909 */ 910 private static Principal getKnownPrincipal(Class<?> claz, String name) { 911 if (claz.equals(X500Principal.class)) { 912 return new X500Principal(name); 913 } else { 914 return null; 915 } 916 } 917 918 /** 919 * Fetch all certs associated with this alias. 920 */ 921 private Certificate[] getCertificates 922 (KeyStore keyStore, String aliases, PolicyInfo newInfo) { 923 924 List<Certificate> vcerts = null; 925 926 StringTokenizer st = new StringTokenizer(aliases, ","); 927 int n = 0; 928 929 while (st.hasMoreTokens()) { 930 String alias = st.nextToken().trim(); 931 n++; 932 Certificate cert = null; 933 // See if this alias's cert has already been cached 934 synchronized (newInfo.aliasMapping) { 935 cert = (Certificate)newInfo.aliasMapping.get(alias); 936 937 if (cert == null && keyStore != null) { 938 939 try { 940 cert = keyStore.getCertificate(alias); 941 } catch (KeyStoreException kse) { 942 // never happens, because keystore has already been loaded 943 // when we call this 944 } 945 if (cert != null) { 946 newInfo.aliasMapping.put(alias, cert); 947 newInfo.aliasMapping.put(cert, alias); 948 } 949 } 950 } 951 952 if (cert != null) { 953 if (vcerts == null) 954 vcerts = new ArrayList<>(); 955 vcerts.add(cert); 956 } 957 } 958 959 // make sure n == vcerts.size, since we are doing a logical *and* 960 if (vcerts != null && n == vcerts.size()) { 961 Certificate[] certs = new Certificate[vcerts.size()]; 962 vcerts.toArray(certs); 963 return certs; 964 } else { 965 return null; 966 } 967 } 968 969 /** 970 * Refreshes the policy object by re-reading all the policy files. 971 */ 972 @Override public void refresh() { 973 init(url); 974 } 975 976 /** 977 * Evaluates the global policy for the permissions granted to 978 * the ProtectionDomain and tests whether the permission is 979 * granted. 980 * 981 * @param pd the ProtectionDomain to test 982 * @param p the Permission object to be tested for implication. 983 * 984 * @return true if "permission" is a proper subset of a permission 985 * granted to this ProtectionDomain. 986 * 987 * @see java.security.ProtectionDomain 988 */ 989 @Override 990 public boolean implies(ProtectionDomain pd, Permission p) { 991 ProtectionDomainCache pdMap = policyInfo.getPdMapping(); 992 PermissionCollection pc = pdMap.get(pd); 993 994 if (pc != null) { 995 return pc.implies(p); 996 } 997 998 pc = getPermissions(pd); 999 if (pc == null) { 1000 return false; 1001 } 1002 1003 // cache mapping of protection domain to its PermissionCollection 1004 pdMap.put(pd, pc); 1005 return pc.implies(p); 1006 } 1007 1008 /** 1009 * Examines this <code>Policy</code> and returns the permissions granted 1010 * to the specified <code>ProtectionDomain</code>. This includes 1011 * the permissions currently associated with the domain as well 1012 * as the policy permissions granted to the domain's 1013 * CodeSource, ClassLoader, and Principals. 1014 * 1015 * <p> Note that this <code>Policy</code> implementation has 1016 * special handling for PrivateCredentialPermissions. 1017 * When this method encounters a <code>PrivateCredentialPermission</code> 1018 * which specifies "self" as the <code>Principal</code> class and name, 1019 * it does not add that <code>Permission</code> to the returned 1020 * <code>PermissionCollection</code>. Instead, it builds 1021 * a new <code>PrivateCredentialPermission</code> 1022 * for each <code>Principal</code> associated with the provided 1023 * <code>Subject</code>. Each new <code>PrivateCredentialPermission</code> 1024 * contains the same Credential class as specified in the 1025 * originally granted permission, as well as the Class and name 1026 * for the respective <code>Principal</code>. 1027 * 1028 * @param domain the Permissions granted to this 1029 * <code>ProtectionDomain</code> are returned. 1030 * 1031 * @return the Permissions granted to the provided 1032 * <code>ProtectionDomain</code>. 1033 */ 1034 @Override 1035 public PermissionCollection getPermissions(ProtectionDomain domain) { 1036 Permissions perms = new Permissions(); 1037 1038 if (domain == null) 1039 return perms; 1040 1041 // first get policy perms 1042 getPermissions(perms, domain); 1043 1044 // add static perms 1045 // - adding static perms after policy perms is necessary 1046 // to avoid a regression for 4301064 1047 PermissionCollection pc = domain.getPermissions(); 1048 if (pc != null) { 1049 synchronized (pc) { 1050 Enumeration<Permission> e = pc.elements(); 1051 while (e.hasMoreElements()) { 1052 perms.add(FilePermCompat.newPermPlusAltPath(e.nextElement())); 1053 } 1054 } 1055 } 1056 1057 return perms; 1058 } 1059 1060 /** 1061 * Examines this Policy and creates a PermissionCollection object with 1062 * the set of permissions for the specified CodeSource. 1063 * 1064 * @param codesource the CodeSource associated with the caller. 1065 * This encapsulates the original location of the code (where the code 1066 * came from) and the public key(s) of its signer. 1067 * 1068 * @return the set of permissions according to the policy. 1069 */ 1070 @Override 1071 public PermissionCollection getPermissions(CodeSource codesource) { 1072 return getPermissions(new Permissions(), codesource); 1073 } 1074 1075 /** 1076 * Examines the global policy and returns the provided Permissions 1077 * object with additional permissions granted to the specified 1078 * ProtectionDomain. 1079 * 1080 * @param perms the Permissions to populate 1081 * @param pd the ProtectionDomain associated with the caller. 1082 * 1083 * @return the set of Permissions according to the policy. 1084 */ 1085 private PermissionCollection getPermissions(Permissions perms, 1086 ProtectionDomain pd ) { 1087 if (debug != null) { 1088 debug.println("getPermissions:\n\t" + printPD(pd)); 1089 } 1090 1091 final CodeSource cs = pd.getCodeSource(); 1092 if (cs == null) 1093 return perms; 1094 1095 CodeSource canonCodeSource = AccessController.doPrivileged( 1096 new java.security.PrivilegedAction<>(){ 1097 @Override 1098 public CodeSource run() { 1099 return canonicalizeCodebase(cs, true); 1100 } 1101 }); 1102 return getPermissions(perms, canonCodeSource, pd.getPrincipals()); 1103 } 1104 1105 /** 1106 * Examines the global policy and returns the provided Permissions 1107 * object with additional permissions granted to the specified 1108 * CodeSource. 1109 * 1110 * @param perms the permissions to populate 1111 * @param cs the codesource associated with the caller. 1112 * This encapsulates the original location of the code (where the code 1113 * came from) and the public key(s) of its signer. 1114 * 1115 * @return the set of permissions according to the policy. 1116 */ 1117 private PermissionCollection getPermissions(Permissions perms, 1118 final CodeSource cs) { 1119 1120 if (cs == null) 1121 return perms; 1122 1123 CodeSource canonCodeSource = AccessController.doPrivileged( 1124 new PrivilegedAction<>(){ 1125 @Override 1126 public CodeSource run() { 1127 return canonicalizeCodebase(cs, true); 1128 } 1129 }); 1130 1131 return getPermissions(perms, canonCodeSource, null); 1132 } 1133 1134 private Permissions getPermissions(Permissions perms, 1135 final CodeSource cs, 1136 Principal[] principals) { 1137 for (PolicyEntry entry : policyInfo.policyEntries) { 1138 addPermissions(perms, cs, principals, entry); 1139 } 1140 1141 return perms; 1142 } 1143 1144 private void addPermissions(Permissions perms, 1145 final CodeSource cs, 1146 Principal[] principals, 1147 final PolicyEntry entry) { 1148 1149 if (debug != null) { 1150 debug.println("evaluate codesources:\n" + 1151 "\tPolicy CodeSource: " + entry.getCodeSource() + "\n" + 1152 "\tActive CodeSource: " + cs); 1153 } 1154 1155 // check to see if the CodeSource implies 1156 Boolean imp = AccessController.doPrivileged 1157 (new PrivilegedAction<>() { 1158 @Override 1159 public Boolean run() { 1160 return entry.getCodeSource().implies(cs); 1161 } 1162 }); 1163 if (!imp.booleanValue()) { 1164 if (debug != null) { 1165 debug.println("evaluation (codesource) failed"); 1166 } 1167 1168 // CodeSource does not imply - return and try next policy entry 1169 return; 1170 } 1171 1172 // check to see if the Principals imply 1173 1174 List<PolicyParser.PrincipalEntry> entryPs = entry.getPrincipals(); 1175 if (debug != null) { 1176 List<PolicyParser.PrincipalEntry> accPs = new ArrayList<>(); 1177 if (principals != null) { 1178 for (int i = 0; i < principals.length; i++) { 1179 accPs.add(new PolicyParser.PrincipalEntry 1180 (principals[i].getClass().getName(), 1181 principals[i].getName())); 1182 } 1183 } 1184 debug.println("evaluate principals:\n" + 1185 "\tPolicy Principals: " + entryPs + "\n" + 1186 "\tActive Principals: " + accPs); 1187 } 1188 1189 if (entryPs == null || entryPs.isEmpty()) { 1190 1191 // policy entry has no principals - 1192 // add perms regardless of principals in current ACC 1193 1194 addPerms(perms, principals, entry); 1195 if (debug != null) { 1196 debug.println("evaluation (codesource/principals) passed"); 1197 } 1198 return; 1199 1200 } else if (principals == null || principals.length == 0) { 1201 1202 // current thread has no principals but this policy entry 1203 // has principals - perms are not added 1204 1205 if (debug != null) { 1206 debug.println("evaluation (principals) failed"); 1207 } 1208 return; 1209 } 1210 1211 // current thread has principals and this policy entry 1212 // has principals. see if policy entry principals match 1213 // principals in current ACC 1214 1215 for (PolicyParser.PrincipalEntry pppe : entryPs) { 1216 1217 // Check for wildcards 1218 if (pppe.isWildcardClass()) { 1219 // a wildcard class matches all principals in current ACC 1220 continue; 1221 } 1222 1223 if (pppe.isWildcardName()) { 1224 // a wildcard name matches any principal with the same class 1225 if (wildcardPrincipalNameImplies(pppe.principalClass, 1226 principals)) { 1227 continue; 1228 } 1229 if (debug != null) { 1230 debug.println("evaluation (principal name wildcard) failed"); 1231 } 1232 // policy entry principal not in current ACC - 1233 // immediately return and go to next policy entry 1234 return; 1235 } 1236 1237 Set<Principal> pSet = new HashSet<>(Arrays.asList(principals)); 1238 Subject subject = new Subject(true, pSet, 1239 Collections.EMPTY_SET, 1240 Collections.EMPTY_SET); 1241 try { 1242 ClassLoader cl = Thread.currentThread().getContextClassLoader(); 1243 Class<?> pClass = Class.forName(pppe.principalClass, false, cl); 1244 Principal p = getKnownPrincipal(pClass, pppe.principalName); 1245 if (p == null) { 1246 if (!Principal.class.isAssignableFrom(pClass)) { 1247 // not the right subtype 1248 throw new ClassCastException(pppe.principalClass + 1249 " is not a Principal"); 1250 } 1251 1252 Constructor<?> c = pClass.getConstructor(PARAMS1); 1253 p = (Principal)c.newInstance(new Object[] { 1254 pppe.principalName }); 1255 1256 } 1257 1258 if (debug != null) { 1259 debug.println("found Principal " + p.getClass().getName()); 1260 } 1261 1262 // check if the Principal implies the current 1263 // thread's principals 1264 if (!p.implies(subject)) { 1265 if (debug != null) { 1266 debug.println("evaluation (principal implies) failed"); 1267 } 1268 1269 // policy principal does not imply the current Subject - 1270 // immediately return and go to next policy entry 1271 return; 1272 } 1273 } catch (Exception e) { 1274 // fall back to default principal comparison. 1275 // see if policy entry principal is in current ACC 1276 1277 if (debug != null) { 1278 e.printStackTrace(); 1279 } 1280 1281 if (!pppe.implies(subject)) { 1282 if (debug != null) { 1283 debug.println("evaluation (default principal implies) failed"); 1284 } 1285 1286 // policy entry principal not in current ACC - 1287 // immediately return and go to next policy entry 1288 return; 1289 } 1290 } 1291 1292 // either the principal information matched, 1293 // or the Principal.implies succeeded. 1294 // continue loop and test the next policy principal 1295 } 1296 1297 // all policy entry principals were found in the current ACC - 1298 // grant the policy permissions 1299 1300 if (debug != null) { 1301 debug.println("evaluation (codesource/principals) passed"); 1302 } 1303 addPerms(perms, principals, entry); 1304 } 1305 1306 /** 1307 * Returns true if the array of principals contains at least one 1308 * principal of the specified class. 1309 */ 1310 private static boolean wildcardPrincipalNameImplies(String principalClass, 1311 Principal[] principals) 1312 { 1313 for (Principal p : principals) { 1314 if (principalClass.equals(p.getClass().getName())) { 1315 return true; 1316 } 1317 } 1318 return false; 1319 } 1320 1321 private void addPerms(Permissions perms, 1322 Principal[] accPs, 1323 PolicyEntry entry) { 1324 for (int i = 0; i < entry.permissions.size(); i++) { 1325 Permission p = entry.permissions.get(i); 1326 if (debug != null) { 1327 debug.println(" granting " + p); 1328 } 1329 1330 if (p instanceof SelfPermission) { 1331 // handle "SELF" permissions 1332 expandSelf((SelfPermission)p, 1333 entry.getPrincipals(), 1334 accPs, 1335 perms); 1336 } else { 1337 perms.add(FilePermCompat.newPermPlusAltPath(p)); 1338 } 1339 } 1340 } 1341 1342 /** 1343 * @param sp the SelfPermission that needs to be expanded. 1344 * 1345 * @param entryPs list of principals for the Policy entry. 1346 * 1347 * @param pdp Principal array from the current ProtectionDomain. 1348 * 1349 * @param perms the PermissionCollection where the individual 1350 * Permissions will be added after expansion. 1351 */ 1352 1353 private void expandSelf(SelfPermission sp, 1354 List<PolicyParser.PrincipalEntry> entryPs, 1355 Principal[] pdp, 1356 Permissions perms) { 1357 1358 if (entryPs == null || entryPs.isEmpty()) { 1359 // No principals in the grant to substitute 1360 if (debug != null) { 1361 debug.println("Ignoring permission " 1362 + sp.getSelfType() 1363 + " with target name (" 1364 + sp.getSelfName() + "). " 1365 + "No Principal(s) specified " 1366 + "in the grant clause. " 1367 + "SELF-based target names are " 1368 + "only valid in the context " 1369 + "of a Principal-based grant entry." 1370 ); 1371 } 1372 return; 1373 } 1374 int startIndex = 0; 1375 int v; 1376 StringBuilder sb = new StringBuilder(); 1377 while ((v = sp.getSelfName().indexOf(SELF, startIndex)) != -1) { 1378 1379 // add non-SELF string 1380 sb.append(sp.getSelfName().substring(startIndex, v)); 1381 1382 // expand SELF 1383 Iterator<PolicyParser.PrincipalEntry> pli = entryPs.iterator(); 1384 while (pli.hasNext()) { 1385 PolicyParser.PrincipalEntry pppe = pli.next(); 1386 String[][] principalInfo = getPrincipalInfo(pppe,pdp); 1387 for (int i = 0; i < principalInfo.length; i++) { 1388 if (i != 0) { 1389 sb.append(", "); 1390 } 1391 sb.append(principalInfo[i][0] + " " + 1392 "\"" + principalInfo[i][1] + "\""); 1393 } 1394 if (pli.hasNext()) { 1395 sb.append(", "); 1396 } 1397 } 1398 startIndex = v + SELF.length(); 1399 } 1400 // add remaining string (might be the entire string) 1401 sb.append(sp.getSelfName().substring(startIndex)); 1402 1403 if (debug != null) { 1404 debug.println(" expanded:\n\t" + sp.getSelfName() 1405 + "\n into:\n\t" + sb.toString()); 1406 } 1407 try { 1408 // first try to instantiate the permission 1409 perms.add(FilePermCompat.newPermPlusAltPath(getInstance(sp.getSelfType(), 1410 sb.toString(), 1411 sp.getSelfActions()))); 1412 } catch (ClassNotFoundException cnfe) { 1413 // ok, the permission is not in the bootclasspath. 1414 // before we add an UnresolvedPermission, check to see 1415 // whether this perm already belongs to the collection. 1416 // if so, use that perm's ClassLoader to create a new 1417 // one. 1418 Class<?> pc = null; 1419 synchronized (perms) { 1420 Enumeration<Permission> e = perms.elements(); 1421 while (e.hasMoreElements()) { 1422 Permission pElement = e.nextElement(); 1423 if (pElement.getClass().getName().equals(sp.getSelfType())) { 1424 pc = pElement.getClass(); 1425 break; 1426 } 1427 } 1428 } 1429 if (pc == null) { 1430 // create an UnresolvedPermission 1431 perms.add(new UnresolvedPermission(sp.getSelfType(), 1432 sb.toString(), 1433 sp.getSelfActions(), 1434 sp.getCerts())); 1435 } else { 1436 try { 1437 // we found an instantiated permission. 1438 // use its class loader to instantiate a new permission. 1439 Constructor<?> c; 1440 // name parameter can not be null 1441 if (sp.getSelfActions() == null) { 1442 try { 1443 c = pc.getConstructor(PARAMS1); 1444 perms.add((Permission)c.newInstance 1445 (new Object[] {sb.toString()})); 1446 } catch (NoSuchMethodException ne) { 1447 c = pc.getConstructor(PARAMS2); 1448 perms.add((Permission)c.newInstance 1449 (new Object[] {sb.toString(), 1450 sp.getSelfActions() })); 1451 } 1452 } else { 1453 c = pc.getConstructor(PARAMS2); 1454 perms.add((Permission)c.newInstance 1455 (new Object[] {sb.toString(), 1456 sp.getSelfActions()})); 1457 } 1458 } catch (Exception nme) { 1459 if (debug != null) { 1460 debug.println("self entry expansion " + 1461 " instantiation failed: " 1462 + nme.toString()); 1463 } 1464 } 1465 } 1466 } catch (Exception e) { 1467 if (debug != null) { 1468 debug.println(e.toString()); 1469 } 1470 } 1471 } 1472 1473 /** 1474 * return the principal class/name pair in the 2D array. 1475 * array[x][y]: x corresponds to the array length. 1476 * if (y == 0), it's the principal class. 1477 * if (y == 1), it's the principal name. 1478 */ 1479 private String[][] getPrincipalInfo 1480 (PolicyParser.PrincipalEntry pe, Principal[] pdp) { 1481 1482 // there are 3 possibilities: 1483 // 1) the entry's Principal class and name are not wildcarded 1484 // 2) the entry's Principal name is wildcarded only 1485 // 3) the entry's Principal class and name are wildcarded 1486 1487 if (!pe.isWildcardClass() && !pe.isWildcardName()) { 1488 1489 // build an info array for the principal 1490 // from the Policy entry 1491 String[][] info = new String[1][2]; 1492 info[0][0] = pe.principalClass; 1493 info[0][1] = pe.principalName; 1494 return info; 1495 1496 } else if (!pe.isWildcardClass() && pe.isWildcardName()) { 1497 1498 // build an info array for every principal 1499 // in the current domain which has a principal class 1500 // that is equal to policy entry principal class name 1501 List<Principal> plist = new ArrayList<>(); 1502 for (int i = 0; i < pdp.length; i++) { 1503 if (pe.principalClass.equals(pdp[i].getClass().getName())) 1504 plist.add(pdp[i]); 1505 } 1506 String[][] info = new String[plist.size()][2]; 1507 int i = 0; 1508 for (Principal p : plist) { 1509 info[i][0] = p.getClass().getName(); 1510 info[i][1] = p.getName(); 1511 i++; 1512 } 1513 return info; 1514 1515 } else { 1516 1517 // build an info array for every 1518 // one of the current Domain's principals 1519 1520 String[][] info = new String[pdp.length][2]; 1521 1522 for (int i = 0; i < pdp.length; i++) { 1523 info[i][0] = pdp[i].getClass().getName(); 1524 info[i][1] = pdp[i].getName(); 1525 } 1526 return info; 1527 } 1528 } 1529 1530 /* 1531 * Returns the signer certificates from the list of certificates 1532 * associated with the given code source. 1533 * 1534 * The signer certificates are those certificates that were used 1535 * to verify signed code originating from the codesource location. 1536 * 1537 * This method assumes that in the given code source, each signer 1538 * certificate is followed by its supporting certificate chain 1539 * (which may be empty), and that the signer certificate and its 1540 * supporting certificate chain are ordered bottom-to-top 1541 * (i.e., with the signer certificate first and the (root) certificate 1542 * authority last). 1543 */ 1544 protected Certificate[] getSignerCertificates(CodeSource cs) { 1545 Certificate[] certs = null; 1546 if ((certs = cs.getCertificates()) == null) 1547 return null; 1548 for (int i=0; i<certs.length; i++) { 1549 if (!(certs[i] instanceof X509Certificate)) 1550 return cs.getCertificates(); 1551 } 1552 1553 // Do we have to do anything? 1554 int i = 0; 1555 int count = 0; 1556 while (i < certs.length) { 1557 count++; 1558 while (((i+1) < certs.length) 1559 && ((X509Certificate)certs[i]).getIssuerDN().equals( 1560 ((X509Certificate)certs[i+1]).getSubjectDN())) { 1561 i++; 1562 } 1563 i++; 1564 } 1565 if (count == certs.length) 1566 // Done 1567 return certs; 1568 1569 List<Certificate> userCertList = new ArrayList<>(); 1570 i = 0; 1571 while (i < certs.length) { 1572 userCertList.add(certs[i]); 1573 while (((i+1) < certs.length) 1574 && ((X509Certificate)certs[i]).getIssuerDN().equals( 1575 ((X509Certificate)certs[i+1]).getSubjectDN())) { 1576 i++; 1577 } 1578 i++; 1579 } 1580 Certificate[] userCerts = new Certificate[userCertList.size()]; 1581 userCertList.toArray(userCerts); 1582 return userCerts; 1583 } 1584 1585 private CodeSource canonicalizeCodebase(CodeSource cs, 1586 boolean extractSignerCerts) { 1587 1588 String path = null; 1589 1590 CodeSource canonCs = cs; 1591 URL u = cs.getLocation(); 1592 if (u != null) { 1593 if (u.getProtocol().equals("jar")) { 1594 // unwrap url embedded inside jar url 1595 String spec = u.getFile(); 1596 int separator = spec.indexOf("!/"); 1597 if (separator != -1) { 1598 try { 1599 u = new URL(spec.substring(0, separator)); 1600 } catch (MalformedURLException e) { 1601 // Fail silently. In this case, url stays what 1602 // it was above 1603 } 1604 } 1605 } 1606 if (u.getProtocol().equals("file")) { 1607 boolean isLocalFile = false; 1608 String host = u.getHost(); 1609 isLocalFile = (host == null || host.isEmpty() || 1610 host.equals("~") || host.equalsIgnoreCase("localhost")); 1611 1612 if (isLocalFile) { 1613 path = u.getFile().replace('/', File.separatorChar); 1614 path = ParseUtil.decode(path); 1615 } 1616 } 1617 } 1618 1619 if (path != null) { 1620 try { 1621 URL csUrl = null; 1622 path = canonPath(path); 1623 csUrl = ParseUtil.fileToEncodedURL(new File(path)); 1624 1625 if (extractSignerCerts) { 1626 canonCs = new CodeSource(csUrl, 1627 getSignerCertificates(cs)); 1628 } else { 1629 canonCs = new CodeSource(csUrl, 1630 cs.getCertificates()); 1631 } 1632 } catch (IOException ioe) { 1633 // leave codesource as it is, unless we have to extract its 1634 // signer certificates 1635 if (extractSignerCerts) { 1636 canonCs = new CodeSource(cs.getLocation(), 1637 getSignerCertificates(cs)); 1638 } 1639 } 1640 } else { 1641 if (extractSignerCerts) { 1642 canonCs = new CodeSource(cs.getLocation(), 1643 getSignerCertificates(cs)); 1644 } 1645 } 1646 return canonCs; 1647 } 1648 1649 // Wrapper to return a canonical path that avoids calling getCanonicalPath() 1650 // with paths that are intended to match all entries in the directory 1651 private static String canonPath(String path) throws IOException { 1652 if (path.endsWith("*")) { 1653 path = path.substring(0, path.length()-1) + "-"; 1654 path = new File(path).getCanonicalPath(); 1655 return path.substring(0, path.length()-1) + "*"; 1656 } else { 1657 return new File(path).getCanonicalPath(); 1658 } 1659 } 1660 1661 private String printPD(ProtectionDomain pd) { 1662 Principal[] principals = pd.getPrincipals(); 1663 String pals = "<no principals>"; 1664 if (principals != null && principals.length > 0) { 1665 StringBuilder palBuf = new StringBuilder("(principals "); 1666 for (int i = 0; i < principals.length; i++) { 1667 palBuf.append(principals[i].getClass().getName() + 1668 " \"" + principals[i].getName() + 1669 "\""); 1670 if (i < principals.length-1) 1671 palBuf.append(", "); 1672 else 1673 palBuf.append(")"); 1674 } 1675 pals = palBuf.toString(); 1676 } 1677 return "PD CodeSource: " 1678 + pd.getCodeSource() 1679 +"\n\t" + "PD ClassLoader: " 1680 + pd.getClassLoader() 1681 +"\n\t" + "PD Principals: " 1682 + pals; 1683 } 1684 1685 /** 1686 * return true if no replacement was performed, 1687 * or if replacement succeeded. 1688 */ 1689 private boolean replacePrincipals( 1690 List<PolicyParser.PrincipalEntry> principals, KeyStore keystore) { 1691 1692 if (principals == null || principals.isEmpty() || keystore == null) 1693 return true; 1694 1695 for (PolicyParser.PrincipalEntry pppe : principals) { 1696 if (pppe.isReplaceName()) { 1697 1698 // perform replacement 1699 // (only X509 replacement is possible now) 1700 String name; 1701 if ((name = getDN(pppe.principalName, keystore)) == null) { 1702 return false; 1703 } 1704 1705 if (debug != null) { 1706 debug.println(" Replacing \"" + 1707 pppe.principalName + 1708 "\" with " + 1709 X500PRINCIPAL + "/\"" + 1710 name + 1711 "\""); 1712 } 1713 1714 pppe.principalClass = X500PRINCIPAL; 1715 pppe.principalName = name; 1716 } 1717 } 1718 // return true if no replacement was performed, 1719 // or if replacement succeeded 1720 return true; 1721 } 1722 1723 private void expandPermissionName(PolicyParser.PermissionEntry pe, 1724 KeyStore keystore) throws Exception { 1725 // short cut the common case 1726 if (pe.name == null || pe.name.indexOf("${{", 0) == -1) { 1727 return; 1728 } 1729 1730 int startIndex = 0; 1731 int b, e; 1732 StringBuilder sb = new StringBuilder(); 1733 while ((b = pe.name.indexOf("${{", startIndex)) != -1) { 1734 e = pe.name.indexOf("}}", b); 1735 if (e < 1) { 1736 break; 1737 } 1738 sb.append(pe.name.substring(startIndex, b)); 1739 1740 // get the value in ${{...}} 1741 String value = pe.name.substring(b+3, e); 1742 1743 // parse up to the first ':' 1744 int colonIndex; 1745 String prefix = value; 1746 String suffix; 1747 if ((colonIndex = value.indexOf(':')) != -1) { 1748 prefix = value.substring(0, colonIndex); 1749 } 1750 1751 // handle different prefix possibilities 1752 if (prefix.equalsIgnoreCase("self")) { 1753 // do nothing - handled later 1754 sb.append(pe.name.substring(b, e+2)); 1755 startIndex = e+2; 1756 continue; 1757 } else if (prefix.equalsIgnoreCase("alias")) { 1758 // get the suffix and perform keystore alias replacement 1759 if (colonIndex == -1) { 1760 Object[] source = {pe.name}; 1761 throw new Exception( 1762 LocalizedMessage.getNonlocalized( 1763 "alias.name.not.provided.pe.name.", 1764 source)); 1765 } 1766 suffix = value.substring(colonIndex+1); 1767 if ((suffix = getDN(suffix, keystore)) == null) { 1768 Object[] source = {value.substring(colonIndex+1)}; 1769 throw new Exception( 1770 LocalizedMessage.getNonlocalized( 1771 "unable.to.perform.substitution.on.alias.suffix", 1772 source)); 1773 } 1774 1775 sb.append(X500PRINCIPAL + " \"" + suffix + "\""); 1776 startIndex = e+2; 1777 } else { 1778 Object[] source = {prefix}; 1779 throw new Exception( 1780 LocalizedMessage.getNonlocalized( 1781 "substitution.value.prefix.unsupported", 1782 source)); 1783 } 1784 } 1785 1786 // copy the rest of the value 1787 sb.append(pe.name.substring(startIndex)); 1788 1789 // replace the name with expanded value 1790 if (debug != null) { 1791 debug.println(" Permission name expanded from:\n\t" + 1792 pe.name + "\nto\n\t" + sb.toString()); 1793 } 1794 pe.name = sb.toString(); 1795 } 1796 1797 private String getDN(String alias, KeyStore keystore) { 1798 Certificate cert = null; 1799 try { 1800 cert = keystore.getCertificate(alias); 1801 } catch (Exception e) { 1802 if (debug != null) { 1803 debug.println(" Error retrieving certificate for '" + 1804 alias + 1805 "': " + 1806 e.toString()); 1807 } 1808 return null; 1809 } 1810 1811 if (cert == null || !(cert instanceof X509Certificate)) { 1812 if (debug != null) { 1813 debug.println(" -- No certificate for '" + 1814 alias + 1815 "' - ignoring entry"); 1816 } 1817 return null; 1818 } else { 1819 X509Certificate x509Cert = (X509Certificate)cert; 1820 1821 // 4702543: X500 names with an EmailAddress 1822 // were encoded incorrectly. create new 1823 // X500Principal name with correct encoding 1824 1825 X500Principal p = new X500Principal 1826 (x509Cert.getSubjectX500Principal().toString()); 1827 return p.getName(); 1828 } 1829 } 1830 1831 /** 1832 * Each entry in the policy configuration file is represented by a 1833 * PolicyEntry object. <p> 1834 * 1835 * A PolicyEntry is a (CodeSource,Permission) pair. The 1836 * CodeSource contains the (URL, PublicKey) that together identify 1837 * where the Java bytecodes come from and who (if anyone) signed 1838 * them. The URL could refer to localhost. The URL could also be 1839 * null, meaning that this policy entry is given to all comers, as 1840 * long as they match the signer field. The signer could be null, 1841 * meaning the code is not signed. <p> 1842 * 1843 * The Permission contains the (Type, Name, Action) triplet. <p> 1844 * 1845 * For now, the Policy object retrieves the public key from the 1846 * X.509 certificate on disk that corresponds to the signedBy 1847 * alias specified in the Policy config file. For reasons of 1848 * efficiency, the Policy object keeps a hashtable of certs already 1849 * read in. This could be replaced by a secure internal key 1850 * store. 1851 * 1852 * <p> 1853 * For example, the entry 1854 * <pre> 1855 * permission java.io.File "/tmp", "read,write", 1856 * signedBy "Duke"; 1857 * </pre> 1858 * is represented internally 1859 * <pre> 1860 * 1861 * FilePermission f = new FilePermission("/tmp", "read,write"); 1862 * PublicKey p = publickeys.get("Duke"); 1863 * URL u = InetAddress.getLocalHost(); 1864 * CodeBase c = new CodeBase( p, u ); 1865 * pe = new PolicyEntry(f, c); 1866 * </pre> 1867 * 1868 * @author Marianne Mueller 1869 * @author Roland Schemers 1870 * @see java.security.CodeSource 1871 * @see java.security.Policy 1872 * @see java.security.Permissions 1873 * @see java.security.ProtectionDomain 1874 */ 1875 private static class PolicyEntry { 1876 1877 private final CodeSource codesource; 1878 final List<Permission> permissions; 1879 private final List<PolicyParser.PrincipalEntry> principals; 1880 1881 /** 1882 * Given a Permission and a CodeSource, create a policy entry. 1883 * 1884 * XXX Decide if/how to add validity fields and "purpose" fields to 1885 * XXX policy entries 1886 * 1887 * @param cs the CodeSource, which encapsulates the URL and the 1888 * public key 1889 * attributes from the policy config file. Validity checks 1890 * are performed on the public key before PolicyEntry is 1891 * called. 1892 * 1893 */ 1894 PolicyEntry(CodeSource cs, List<PolicyParser.PrincipalEntry> principals) 1895 { 1896 this.codesource = cs; 1897 this.permissions = new ArrayList<Permission>(); 1898 this.principals = principals; // can be null 1899 } 1900 1901 PolicyEntry(CodeSource cs) 1902 { 1903 this(cs, null); 1904 } 1905 1906 List<PolicyParser.PrincipalEntry> getPrincipals() { 1907 return principals; // can be null 1908 } 1909 1910 /** 1911 * add a Permission object to this entry. 1912 * No need to sync add op because perms are added to entry only 1913 * while entry is being initialized 1914 */ 1915 void add(Permission p) { 1916 permissions.add(p); 1917 } 1918 1919 /** 1920 * Return the CodeSource for this policy entry 1921 */ 1922 CodeSource getCodeSource() { 1923 return codesource; 1924 } 1925 1926 @Override public String toString(){ 1927 StringBuilder sb = new StringBuilder(); 1928 sb.append(ResourcesMgr.getString("LPARAM")); 1929 sb.append(getCodeSource()); 1930 sb.append("\n"); 1931 for (int j = 0; j < permissions.size(); j++) { 1932 Permission p = permissions.get(j); 1933 sb.append(ResourcesMgr.getString("SPACE")); 1934 sb.append(ResourcesMgr.getString("SPACE")); 1935 sb.append(p); 1936 sb.append(ResourcesMgr.getString("NEWLINE")); 1937 } 1938 sb.append(ResourcesMgr.getString("RPARAM")); 1939 sb.append(ResourcesMgr.getString("NEWLINE")); 1940 return sb.toString(); 1941 } 1942 } 1943 1944 private static class SelfPermission extends Permission { 1945 1946 @java.io.Serial 1947 private static final long serialVersionUID = -8315562579967246806L; 1948 1949 /** 1950 * The class name of the Permission class that will be 1951 * created when this self permission is expanded . 1952 * 1953 * @serial 1954 */ 1955 private String type; 1956 1957 /** 1958 * The permission name. 1959 * 1960 * @serial 1961 */ 1962 private String name; 1963 1964 /** 1965 * The actions of the permission. 1966 * 1967 * @serial 1968 */ 1969 private String actions; 1970 1971 /** 1972 * The certs of the permission. 1973 * 1974 * @serial 1975 */ 1976 private Certificate[] certs; 1977 1978 /** 1979 * Creates a new SelfPermission containing the permission 1980 * information needed later to expand the self 1981 * @param type the class name of the Permission class that will be 1982 * created when this permission is expanded and if necessary resolved. 1983 * @param name the name of the permission. 1984 * @param actions the actions of the permission. 1985 * @param certs the certificates the permission's class was signed with. 1986 * This is a list of certificate chains, where each chain is composed of 1987 * a signer certificate and optionally its supporting certificate chain. 1988 * Each chain is ordered bottom-to-top (i.e., with the signer 1989 * certificate first and the (root) certificate authority last). 1990 */ 1991 public SelfPermission(String type, String name, String actions, 1992 Certificate[] certs) 1993 { 1994 super(type); 1995 if (type == null) { 1996 throw new NullPointerException 1997 (LocalizedMessage.getNonlocalized("type.can.t.be.null")); 1998 } 1999 this.type = type; 2000 this.name = name; 2001 this.actions = actions; 2002 if (certs != null) { 2003 // Extract the signer certs from the list of certificates. 2004 for (int i=0; i<certs.length; i++) { 2005 if (!(certs[i] instanceof X509Certificate)) { 2006 // there is no concept of signer certs, so we store the 2007 // entire cert array 2008 this.certs = certs.clone(); 2009 break; 2010 } 2011 } 2012 2013 if (this.certs == null) { 2014 // Go through the list of certs and see if all the certs are 2015 // signer certs. 2016 int i = 0; 2017 int count = 0; 2018 while (i < certs.length) { 2019 count++; 2020 while (((i+1) < certs.length) && 2021 ((X509Certificate)certs[i]).getIssuerDN().equals( 2022 ((X509Certificate)certs[i+1]).getSubjectDN())) { 2023 i++; 2024 } 2025 i++; 2026 } 2027 if (count == certs.length) { 2028 // All the certs are signer certs, so we store the 2029 // entire array 2030 this.certs = certs.clone(); 2031 } 2032 2033 if (this.certs == null) { 2034 // extract the signer certs 2035 List<Certificate> signerCerts = new ArrayList<>(); 2036 i = 0; 2037 while (i < certs.length) { 2038 signerCerts.add(certs[i]); 2039 while (((i+1) < certs.length) && 2040 ((X509Certificate)certs[i]).getIssuerDN().equals( 2041 ((X509Certificate)certs[i+1]).getSubjectDN())) { 2042 i++; 2043 } 2044 i++; 2045 } 2046 this.certs = new Certificate[signerCerts.size()]; 2047 signerCerts.toArray(this.certs); 2048 } 2049 } 2050 } 2051 } 2052 2053 /** 2054 * This method always returns false for SelfPermission permissions. 2055 * That is, an SelfPermission never considered to 2056 * imply another permission. 2057 * 2058 * @param p the permission to check against. 2059 * 2060 * @return false. 2061 */ 2062 @Override public boolean implies(Permission p) { 2063 return false; 2064 } 2065 2066 /** 2067 * Checks two SelfPermission objects for equality. 2068 * 2069 * Checks that <i>obj</i> is an SelfPermission, and has 2070 * the same type (class) name, permission name, actions, and 2071 * certificates as this object. 2072 * 2073 * @param obj the object we are testing for equality with this object. 2074 * 2075 * @return true if obj is an SelfPermission, and has the same 2076 * type (class) name, permission name, actions, and 2077 * certificates as this object. 2078 */ 2079 @Override public boolean equals(Object obj) { 2080 if (obj == this) 2081 return true; 2082 2083 if (! (obj instanceof SelfPermission)) 2084 return false; 2085 SelfPermission that = (SelfPermission) obj; 2086 2087 if (!(this.type.equals(that.type) && 2088 this.name.equals(that.name) && 2089 this.actions.equals(that.actions))) 2090 return false; 2091 2092 if (this.certs.length != that.certs.length) 2093 return false; 2094 2095 int i,j; 2096 boolean match; 2097 2098 for (i = 0; i < this.certs.length; i++) { 2099 match = false; 2100 for (j = 0; j < that.certs.length; j++) { 2101 if (this.certs[i].equals(that.certs[j])) { 2102 match = true; 2103 break; 2104 } 2105 } 2106 if (!match) return false; 2107 } 2108 2109 for (i = 0; i < that.certs.length; i++) { 2110 match = false; 2111 for (j = 0; j < this.certs.length; j++) { 2112 if (that.certs[i].equals(this.certs[j])) { 2113 match = true; 2114 break; 2115 } 2116 } 2117 if (!match) return false; 2118 } 2119 return true; 2120 } 2121 2122 /** 2123 * Returns the hash code value for this object. 2124 * 2125 * @return a hash code value for this object. 2126 */ 2127 @Override public int hashCode() { 2128 int hash = type.hashCode(); 2129 if (name != null) 2130 hash ^= name.hashCode(); 2131 if (actions != null) 2132 hash ^= actions.hashCode(); 2133 return hash; 2134 } 2135 2136 /** 2137 * Returns the canonical string representation of the actions, 2138 * which currently is the empty string "", since there are no actions 2139 * for an SelfPermission. That is, the actions for the 2140 * permission that will be created when this SelfPermission 2141 * is resolved may be non-null, but an SelfPermission 2142 * itself is never considered to have any actions. 2143 * 2144 * @return the empty string "". 2145 */ 2146 @Override public String getActions() { 2147 return ""; 2148 } 2149 2150 public String getSelfType() { 2151 return type; 2152 } 2153 2154 public String getSelfName() { 2155 return name; 2156 } 2157 2158 public String getSelfActions() { 2159 return actions; 2160 } 2161 2162 public Certificate[] getCerts() { 2163 return certs; 2164 } 2165 2166 /** 2167 * Returns a string describing this SelfPermission. The convention 2168 * is to specify the class name, the permission name, and the actions, 2169 * in the following format: '(unresolved "ClassName" "name" "actions")'. 2170 * 2171 * @return information about this SelfPermission. 2172 */ 2173 @Override public String toString() { 2174 return "(SelfPermission " + type + " " + name + " " + actions + ")"; 2175 } 2176 } 2177 2178 /** 2179 * holds policy information that we need to synch on 2180 */ 2181 private static class PolicyInfo { 2182 private static final boolean verbose = false; 2183 2184 // Stores grant entries in the policy 2185 final List<PolicyEntry> policyEntries; 2186 2187 // Maps aliases to certs 2188 final Map<Object, Object> aliasMapping; 2189 2190 // Maps ProtectionDomain to PermissionCollection 2191 private final ProtectionDomainCache[] pdMapping; 2192 private java.util.Random random; 2193 2194 PolicyInfo(int numCaches) { 2195 policyEntries = new ArrayList<>(); 2196 aliasMapping = Collections.synchronizedMap(new HashMap<>(11)); 2197 2198 pdMapping = new ProtectionDomainCache[numCaches]; 2199 JavaSecurityAccess jspda 2200 = SharedSecrets.getJavaSecurityAccess(); 2201 for (int i = 0; i < numCaches; i++) { 2202 pdMapping[i] = jspda.getProtectionDomainCache(); 2203 } 2204 if (numCaches > 1) { 2205 random = new java.util.Random(); 2206 } 2207 } 2208 ProtectionDomainCache getPdMapping() { 2209 if (pdMapping.length == 1) { 2210 return pdMapping[0]; 2211 } else { 2212 int i = java.lang.Math.abs(random.nextInt() % pdMapping.length); 2213 return pdMapping[i]; 2214 } 2215 } 2216 } 2217 }