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