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