1 /*
   2  * Copyright (c) 1999, 2012, 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 com.sun.security.auth;
  27 
  28 import java.io.*;
  29 import java.lang.reflect.*;
  30 import java.net.URL;
  31 import java.util.*;
  32 
  33 import java.security.CodeSource;
  34 import java.security.KeyStore;
  35 import java.security.KeyStoreException;
  36 import java.security.Permission;
  37 import java.security.Permissions;
  38 import java.security.PermissionCollection;
  39 import java.security.Principal;
  40 import java.security.UnresolvedPermission;
  41 import java.security.Security;
  42 import java.security.cert.Certificate;
  43 import java.security.cert.X509Certificate;
  44 
  45 import javax.security.auth.Subject;
  46 import javax.security.auth.PrivateCredentialPermission;
  47 
  48 import sun.security.util.PropertyExpander;
  49 
  50 /**
  51  * This class represents a default implementation for
  52  * <code>javax.security.auth.Policy</code>.
  53  *
  54  * <p> This object stores the policy for entire Java runtime,
  55  * and is the amalgamation of multiple static policy
  56  * configurations that resides in files.
  57  * The algorithm for locating the policy file(s) and reading their
  58  * information into this <code>Policy</code> object is:
  59  *
  60  * <ol>
  61  * <li>
  62  *   Loop through the security properties,
  63  *   <i>auth.policy.url.1</i>, <i>auth.policy.url.2</i>, ...,
  64  *   <i>auth.policy.url.X</i>".
  65  *   Each property value specifies a <code>URL</code> pointing to a
  66  *   policy file to be loaded.  Read in and load each policy.
  67  *
  68  * <li>
  69  *   The <code>java.lang.System</code> property <i>java.security.auth.policy</i>
  70  *   may also be set to a <code>URL</code> pointing to another policy file
  71  *   (which is the case when a user uses the -D switch at runtime).
  72  *   If this property is defined, and its use is allowed by the
  73  *   security property file (the Security property,
  74  *   <i>policy.allowSystemProperty</i> is set to <i>true</i>),
  75  *   also load that policy.
  76  *
  77  * <li>
  78  *   If the <i>java.security.auth.policy</i> property is defined using
  79  *   "==" (rather than "="), then ignore all other specified
  80  *   policies and only load this policy.
  81  * </ol>
  82  *
  83  * Each policy file consists of one or more grant entries, each of
  84  * which consists of a number of permission entries.
  85  *
  86  * <pre>
  87  *   grant signedBy "<b>alias</b>", codeBase "<b>URL</b>",
  88  *         principal <b>principalClass</b> "<b>principalName</b>",
  89  *         principal <b>principalClass</b> "<b>principalName</b>",
  90  *         ... {
  91  *
  92  *     permission <b>Type</b> "<b>name</b> "<b>action</b>",
  93  *         signedBy "<b>alias</b>";
  94  *     permission <b>Type</b> "<b>name</b> "<b>action</b>",
  95  *         signedBy "<b>alias</b>";
  96  *     ....
  97  *   };
  98  * </pre>
  99  *
 100  * All non-bold items above must appear as is (although case
 101  * doesn't matter and some are optional, as noted below).
 102  * Italicized items represent variable values.
 103  *
 104  * <p> A grant entry must begin with the word <code>grant</code>.
 105  * The <code>signedBy</code> and <code>codeBase</code>
 106  * name/value pairs are optional.
 107  * If they are not present, then any signer (including unsigned code)
 108  * will match, and any codeBase will match.  Note that the
 109  * <code>principal</code> name/value pair is not optional.
 110  * This <code>Policy</code> implementation only permits
 111  * Principal-based grant entries.  Note that the <i>principalClass</i>
 112  * may be set to the wildcard value, *, which allows it to match
 113  * any <code>Principal</code> class.  In addition, the <i>principalName</i>
 114  * may also be set to the wildcard value, *, allowing it to match
 115  * any <code>Principal</code> name.  When setting the <i>principalName</i>
 116  * to the *, do not surround the * with quotes.
 117  *
 118  * <p> A permission entry must begin with the word <code>permission</code>.
 119  * The word <code><i>Type</i></code> in the template above is
 120  * a specific permission type, such as <code>java.io.FilePermission</code>
 121  * or <code>java.lang.RuntimePermission</code>.
 122  *
 123  * <p> The "<i>action</i>" is required for
 124  * many permission types, such as <code>java.io.FilePermission</code>
 125  * (where it specifies what type of file access that is permitted).
 126  * It is not required for categories such as
 127  * <code>java.lang.RuntimePermission</code>
 128  * where it is not necessary - you either have the
 129  * permission specified by the <code>"<i>name</i>"</code>
 130  * value following the type name or you don't.
 131  *
 132  * <p> The <code>signedBy</code> name/value pair for a permission entry
 133  * is optional. If present, it indicates a signed permission. That is,
 134  * the permission class itself must be signed by the given alias in
 135  * order for it to be granted. For example,
 136  * suppose you have the following grant entry:
 137  *
 138  * <pre>
 139  *   grant principal foo.com.Principal "Duke" {
 140  *     permission Foo "foobar", signedBy "FooSoft";
 141  *   }
 142  * </pre>
 143  *
 144  * <p> Then this permission of type <i>Foo</i> is granted if the
 145  * <code>Foo.class</code> permission has been signed by the
 146  * "FooSoft" alias, or if <code>Foo.class</code> is a
 147  * system class (i.e., is found on the CLASSPATH).
 148  *
 149  * <p> Items that appear in an entry must appear in the specified order
 150  * (<code>permission</code>, <i>Type</i>, "<i>name</i>", and
 151  * "<i>action</i>"). An entry is terminated with a semicolon.
 152  *
 153  * <p> Case is unimportant for the identifiers (<code>permission</code>,
 154  * <code>signedBy</code>, <code>codeBase</code>, etc.) but is
 155  * significant for the <i>Type</i>
 156  * or for any string that is passed in as a value. <p>
 157  *
 158  * <p> An example of two entries in a policy configuration file is
 159  * <pre>
 160  *   // if the code is comes from "foo.com" and is running as "Duke",
 161  *   // grant it read/write to all files in /tmp.
 162  *
 163  *   grant codeBase "foo.com", principal foo.com.Principal "Duke" {
 164  *              permission java.io.FilePermission "/tmp/*", "read,write";
 165  *   };
 166  *
 167  *   // grant any code running as "Duke" permission to read
 168  *   // the "java.vendor" Property.
 169  *
 170  *   grant principal foo.com.Principal "Duke" {
 171  *         permission java.util.PropertyPermission "java.vendor";
 172  * </pre>
 173  *
 174  * <p> This <code>Policy</code> implementation supports
 175  * special handling for PrivateCredentialPermissions.
 176  * If a grant entry is configured with a
 177  * <code>PrivateCredentialPermission</code>,
 178  * and the "Principal Class/Principal Name" for that
 179  * <code>PrivateCredentialPermission</code> is "self",
 180  * then the entry grants the specified <code>Subject</code> permission to
 181  * access its own private Credential.  For example,
 182  * the following grants the <code>Subject</code> "Duke"
 183  * access to its own a.b.Credential.
 184  *
 185  * <pre>
 186  *   grant principal foo.com.Principal "Duke" {
 187  *      permission javax.security.auth.PrivateCredentialPermission
 188  *              "a.b.Credential self",
 189  *              "read";
 190  *    };
 191  * </pre>
 192  *
 193  * The following grants the <code>Subject</code> "Duke"
 194  * access to all of its own private Credentials:
 195  *
 196  * <pre>
 197  *   grant principal foo.com.Principal "Duke" {
 198  *      permission javax.security.auth.PrivateCredentialPermission
 199  *              "* self",
 200  *              "read";
 201  *    };
 202  * </pre>
 203  *
 204  * The following grants all Subjects authenticated as a
 205  * <code>SolarisPrincipal</code> (regardless of their respective names)
 206  * permission to access their own private Credentials:
 207  *
 208  * <pre>
 209  *   grant principal com.sun.security.auth.SolarisPrincipal * {
 210  *      permission javax.security.auth.PrivateCredentialPermission
 211  *              "* self",
 212  *              "read";
 213  *    };
 214  * </pre>
 215  *
 216  * The following grants all Subjects permission to access their own
 217  * private Credentials:
 218  *
 219  * <pre>
 220  *   grant principal * * {
 221  *      permission javax.security.auth.PrivateCredentialPermission
 222  *              "* self",
 223  *              "read";
 224  *    };
 225  * </pre>
 226 
 227  * @deprecated As of JDK&nbsp;1.4, replaced by
 228  *             <code>sun.security.provider.PolicyFile</code>.
 229  *             This class is entirely deprecated.
 230  *
 231  * @see java.security.CodeSource
 232  * @see java.security.Permissions
 233  * @see java.security.ProtectionDomain
 234  * @see java.security.Security security properties
 235  */
 236 @jdk.Supported
 237 @Deprecated
 238 public class PolicyFile extends javax.security.auth.Policy {
 239 
 240     static final java.util.ResourceBundle rb =
 241         java.security.AccessController.doPrivileged
 242         (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
 243             public java.util.ResourceBundle run() {
 244                 return (java.util.ResourceBundle.getBundle
 245                         ("sun.security.util.AuthResources"));
 246             }
 247         });
 248     // needs to be package private
 249 
 250     private static final sun.security.util.Debug debug =
 251         sun.security.util.Debug.getInstance("policy", "\t[Auth Policy]");
 252 
 253     private static final String AUTH_POLICY = "java.security.auth.policy";
 254     private static final String SECURITY_MANAGER = "java.security.manager";
 255     private static final String AUTH_POLICY_URL = "auth.policy.url.";
 256 
 257     private Vector<PolicyEntry> policyEntries;
 258     private Hashtable<Object, Object> aliasMapping;
 259 
 260     private boolean initialized = false;
 261 
 262     private boolean expandProperties = true;
 263     private boolean ignoreIdentityScope = true;
 264 
 265     // for use with the reflection API
 266 
 267     private static final Class[] PARAMS = { String.class, String.class};
 268 
 269     /**
 270      * Initializes the Policy object and reads the default policy
 271      * configuration file(s) into the Policy object.
 272      */
 273     public PolicyFile() {
 274         // initialize Policy if either the AUTH_POLICY or
 275         // SECURITY_MANAGER properties are set
 276         String prop = System.getProperty(AUTH_POLICY);
 277 
 278         if (prop == null) {
 279             prop = System.getProperty(SECURITY_MANAGER);
 280         }
 281         if (prop != null)
 282             init();
 283     }
 284 
 285     private synchronized void init() {
 286 
 287         if (initialized)
 288             return;
 289 
 290         policyEntries = new Vector<PolicyEntry>();
 291         aliasMapping = new Hashtable<Object, Object>(11);
 292 
 293         initPolicyFile();
 294         initialized = true;
 295     }
 296 
 297     /**
 298      * Refreshes the policy object by re-reading all the policy files.
 299      *
 300      * <p>
 301      *
 302      * @exception SecurityException if the caller doesn't have permission
 303      *          to refresh the <code>Policy</code>.
 304      */
 305     public synchronized void refresh()
 306     {
 307 
 308         java.lang.SecurityManager sm = System.getSecurityManager();
 309         if (sm != null) {
 310             sm.checkPermission(new javax.security.auth.AuthPermission
 311                                 ("refreshPolicy"));
 312         }
 313 
 314         // XXX
 315         //
 316         // 1)   if code instantiates PolicyFile directly, then it will need
 317         //      all the permissions required for the PolicyFile initialization
 318         // 2)   if code calls Policy.getPolicy, then it simply needs
 319         //      AuthPermission(getPolicy), and the javax.security.auth.Policy
 320         //      implementation instantiates PolicyFile in a doPrivileged block
 321         // 3)   if after instantiating a Policy (either via #1 or #2),
 322         //      code calls refresh, it simply needs
 323         //      AuthPermission(refreshPolicy).  then PolicyFile wraps
 324         //      the refresh in a doPrivileged block.
 325         initialized = false;
 326         java.security.AccessController.doPrivileged
 327             (new java.security.PrivilegedAction<Void>() {
 328             public Void run() {
 329                 init();
 330                 return null;
 331             }
 332         });
 333     }
 334 
 335     private KeyStore initKeyStore(URL policyUrl, String keyStoreName,
 336                                   String keyStoreType) {
 337         if (keyStoreName != null) {
 338             try {
 339                 /*
 340                  * location of keystore is specified as absolute URL in policy
 341                  * file, or is relative to URL of policy file
 342                  */
 343                 URL keyStoreUrl = null;
 344                 try {
 345                     keyStoreUrl = new URL(keyStoreName);
 346                     // absolute URL
 347                 } catch (java.net.MalformedURLException e) {
 348                     // relative URL
 349                     keyStoreUrl = new URL(policyUrl, keyStoreName);
 350                 }
 351 
 352                 if (debug != null) {
 353                     debug.println("reading keystore"+keyStoreUrl);
 354                 }
 355 
 356                 InputStream inStream =
 357                     new BufferedInputStream(getInputStream(keyStoreUrl));
 358 
 359                 KeyStore ks;
 360                 if (keyStoreType != null)
 361                     ks = KeyStore.getInstance(keyStoreType);
 362                 else
 363                     ks = KeyStore.getInstance(KeyStore.getDefaultType());
 364                 ks.load(inStream, null);
 365                 inStream.close();
 366                 return ks;
 367             } catch (Exception e) {
 368                 // ignore, treat it like we have no keystore
 369                 if (debug != null) {
 370                     e.printStackTrace();
 371                 }
 372                 return null;
 373             }
 374         }
 375         return null;
 376     }
 377 
 378     private void initPolicyFile() {
 379 
 380         String prop = Security.getProperty("policy.expandProperties");
 381 
 382         if (prop != null) expandProperties = prop.equalsIgnoreCase("true");
 383 
 384         String iscp = Security.getProperty("policy.ignoreIdentityScope");
 385 
 386         if (iscp != null) ignoreIdentityScope = iscp.equalsIgnoreCase("true");
 387 
 388         String allowSys  = Security.getProperty("policy.allowSystemProperty");
 389 
 390         if ((allowSys!=null) && allowSys.equalsIgnoreCase("true")) {
 391 
 392             String extra_policy = System.getProperty(AUTH_POLICY);
 393             if (extra_policy != null) {
 394                 boolean overrideAll = false;
 395                 if (extra_policy.startsWith("=")) {
 396                     overrideAll = true;
 397                     extra_policy = extra_policy.substring(1);
 398                 }
 399                 try {
 400                     extra_policy = PropertyExpander.expand(extra_policy);
 401                     URL policyURL;
 402                     File policyFile = new File(extra_policy);
 403                     if (policyFile.exists()) {
 404                         policyURL =
 405                             new URL("file:" + policyFile.getCanonicalPath());
 406                     } else {
 407                         policyURL = new URL(extra_policy);
 408                     }
 409                     if (debug != null)
 410                         debug.println("reading "+policyURL);
 411                     init(policyURL);
 412                 } catch (Exception e) {
 413                     // ignore.
 414                     if (debug != null) {
 415                         debug.println("caught exception: "+e);
 416                     }
 417 
 418                 }
 419                 if (overrideAll) {
 420                     if (debug != null) {
 421                         debug.println("overriding other policies!");
 422                     }
 423                     return;
 424                 }
 425             }
 426         }
 427 
 428         int n = 1;
 429         boolean loaded_one = false;
 430         String policy_url;
 431 
 432         while ((policy_url = Security.getProperty(AUTH_POLICY_URL+n)) != null) {
 433             try {
 434                 policy_url = PropertyExpander.expand(policy_url).replace
 435                                                 (File.separatorChar, '/');
 436                 if (debug != null)
 437                     debug.println("reading "+policy_url);
 438                 init(new URL(policy_url));
 439                 loaded_one = true;
 440             } catch (Exception e) {
 441                 if (debug != null) {
 442                     debug.println("error reading policy "+e);
 443                     e.printStackTrace();
 444                 }
 445                 // ignore that policy
 446             }
 447             n++;
 448         }
 449 
 450         if (loaded_one == false) {
 451             // do not load a static policy
 452         }
 453     }
 454 
 455     /**
 456      * Checks public key. If it is marked as trusted in
 457      * the identity database, add it to the policy
 458      * with the AllPermission.
 459      */
 460     private boolean checkForTrustedIdentity(final Certificate cert) {
 461         // XXX  JAAS has no way to access the SUN package.
 462         //      we'll add this back in when JAAS goes into core.
 463         return false;
 464     }
 465 
 466     /**
 467      * Reads a policy configuration into the Policy object using a
 468      * Reader object.
 469      *
 470      * @param policyFile the policy Reader object.
 471      */
 472     private void init(URL policy) {
 473         PolicyParser pp = new PolicyParser(expandProperties);
 474         try {
 475             InputStreamReader isr
 476                 = new InputStreamReader(getInputStream(policy));
 477             pp.read(isr);
 478             isr.close();
 479             KeyStore keyStore = initKeyStore(policy, pp.getKeyStoreUrl(),
 480                                              pp.getKeyStoreType());
 481             Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
 482             while (enum_.hasMoreElements()) {
 483                 PolicyParser.GrantEntry ge = enum_.nextElement();
 484                 addGrantEntry(ge, keyStore);
 485             }
 486         } catch (PolicyParser.ParsingException pe) {
 487             System.err.println(AUTH_POLICY +
 488                                 rb.getString(".error.parsing.") + policy);
 489             System.err.println(AUTH_POLICY +
 490                                 rb.getString("COLON") +
 491                                 pe.getMessage());
 492             if (debug != null)
 493                 pe.printStackTrace();
 494 
 495         } catch (Exception e) {
 496             if (debug != null) {
 497                 debug.println("error parsing "+policy);
 498                 debug.println(e.toString());
 499                 e.printStackTrace();
 500             }
 501         }
 502     }
 503 
 504     /*
 505      * Fast path reading from file urls in order to avoid calling
 506      * FileURLConnection.connect() which can be quite slow the first time
 507      * it is called. We really should clean up FileURLConnection so that
 508      * this is not a problem but in the meantime this fix helps reduce
 509      * start up time noticeably for the new launcher. -- DAC
 510      */
 511     private InputStream getInputStream(URL url) throws IOException {
 512         if ("file".equals(url.getProtocol())) {
 513             String path = url.getFile().replace('/', File.separatorChar);
 514             return new FileInputStream(path);
 515         } else {
 516             return url.openStream();
 517         }
 518     }
 519 
 520     /**
 521      * Given a PermissionEntry, create a codeSource.
 522      *
 523      * @return null if signedBy alias is not recognized
 524      */
 525     CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore)
 526         throws java.net.MalformedURLException
 527     {
 528         Certificate[] certs = null;
 529         if (ge.signedBy != null) {
 530             certs = getCertificates(keyStore, ge.signedBy);
 531             if (certs == null) {
 532                 // we don't have a key for this alias,
 533                 // just return
 534                 if (debug != null) {
 535                     debug.println(" no certs for alias " +
 536                                        ge.signedBy + ", ignoring.");
 537                 }
 538                 return null;
 539             }
 540         }
 541 
 542         URL location;
 543 
 544         if (ge.codeBase != null)
 545             location = new URL(ge.codeBase);
 546         else
 547             location = null;
 548 
 549         if (ge.principals == null || ge.principals.size() == 0) {
 550             return (canonicalizeCodebase
 551                         (new CodeSource(location, certs),
 552                         false));
 553         } else {
 554             return (canonicalizeCodebase
 555                 (new SubjectCodeSource(null, ge.principals, location, certs),
 556                 false));
 557         }
 558     }
 559 
 560     /**
 561      * Add one policy entry to the vector.
 562      */
 563     private void addGrantEntry(PolicyParser.GrantEntry ge,
 564                                KeyStore keyStore) {
 565 
 566         if (debug != null) {
 567             debug.println("Adding policy entry: ");
 568             debug.println("  signedBy " + ge.signedBy);
 569             debug.println("  codeBase " + ge.codeBase);
 570             if (ge.principals != null && ge.principals.size() > 0) {
 571                 ListIterator<PolicyParser.PrincipalEntry> li =
 572                                                 ge.principals.listIterator();
 573                 while (li.hasNext()) {
 574                     PolicyParser.PrincipalEntry pppe = li.next();
 575                     debug.println("  " + pppe.principalClass +
 576                                         " " + pppe.principalName);
 577                 }
 578             }
 579             debug.println();
 580         }
 581 
 582         try {
 583             CodeSource codesource = getCodeSource(ge, keyStore);
 584             // skip if signedBy alias was unknown...
 585             if (codesource == null) return;
 586 
 587             PolicyEntry entry = new PolicyEntry(codesource);
 588             Enumeration<PolicyParser.PermissionEntry> enum_ =
 589                                                 ge.permissionElements();
 590             while (enum_.hasMoreElements()) {
 591                 PolicyParser.PermissionEntry pe = enum_.nextElement();
 592                 try {
 593                     // XXX special case PrivateCredentialPermission-SELF
 594                     Permission perm;
 595                     if (pe.permission.equals
 596                         ("javax.security.auth.PrivateCredentialPermission") &&
 597                         pe.name.endsWith(" self")) {
 598                         perm = getInstance(pe.permission,
 599                                          pe.name + " \"self\"",
 600                                          pe.action);
 601                     } else {
 602                         perm = getInstance(pe.permission,
 603                                          pe.name,
 604                                          pe.action);
 605                     }
 606                     entry.add(perm);
 607                     if (debug != null) {
 608                         debug.println("  "+perm);
 609                     }
 610                 } catch (ClassNotFoundException cnfe) {
 611                     Certificate certs[];
 612                     if (pe.signedBy != null)
 613                         certs = getCertificates(keyStore, pe.signedBy);
 614                     else
 615                         certs = null;
 616 
 617                     // only add if we had no signer or we had a
 618                     // a signer and found the keys for it.
 619                     if (certs != null || pe.signedBy == null) {
 620                             Permission perm = new UnresolvedPermission(
 621                                              pe.permission,
 622                                              pe.name,
 623                                              pe.action,
 624                                              certs);
 625                             entry.add(perm);
 626                             if (debug != null) {
 627                                 debug.println("  "+perm);
 628                             }
 629                     }
 630                 } catch (java.lang.reflect.InvocationTargetException ite) {
 631                     System.err.println
 632                         (AUTH_POLICY +
 633                         rb.getString(".error.adding.Permission.") +
 634                         pe.permission +
 635                         rb.getString("SPACE") +
 636                         ite.getTargetException());
 637                 } catch (Exception e) {
 638                     System.err.println
 639                         (AUTH_POLICY +
 640                         rb.getString(".error.adding.Permission.") +
 641                         pe.permission +
 642                         rb.getString("SPACE") +
 643                         e);
 644                 }
 645             }
 646             policyEntries.addElement(entry);
 647         } catch (Exception e) {
 648             System.err.println
 649                 (AUTH_POLICY +
 650                 rb.getString(".error.adding.Entry.") +
 651                 ge +
 652                 rb.getString("SPACE") +
 653                 e);
 654         }
 655 
 656         if (debug != null)
 657             debug.println();
 658     }
 659 
 660     /**
 661      * Returns a new Permission object of the given Type. The Permission is
 662      * created by getting the
 663      * Class object using the <code>Class.forName</code> method, and using
 664      * the reflection API to invoke the (String name, String actions)
 665      * constructor on the
 666      * object.
 667      *
 668      * @param type the type of Permission being created.
 669      * @param name the name of the Permission being created.
 670      * @param actions the actions of the Permission being created.
 671      *
 672      * @exception  ClassNotFoundException  if the particular Permission
 673      *             class could not be found.
 674      *
 675      * @exception  IllegalAccessException  if the class or initializer is
 676      *               not accessible.
 677      *
 678      * @exception  InstantiationException  if getInstance tries to
 679      *               instantiate an abstract class or an interface, or if the
 680      *               instantiation fails for some other reason.
 681      *
 682      * @exception  NoSuchMethodException if the (String, String) constructor
 683      *               is not found.
 684      *
 685      * @exception  InvocationTargetException if the underlying Permission
 686      *               constructor throws an exception.
 687      *
 688      */
 689 
 690     private static final Permission getInstance(String type,
 691                                     String name,
 692                                     String actions)
 693         throws ClassNotFoundException,
 694                InstantiationException,
 695                IllegalAccessException,
 696                NoSuchMethodException,
 697                InvocationTargetException
 698     {
 699         //XXX we might want to keep a hash of created factories...
 700         Class<?> pc = Class.forName(type);
 701         Constructor<?> c = pc.getConstructor(PARAMS);
 702         return (Permission) c.newInstance(new Object[] { name, actions });
 703     }
 704 
 705     /**
 706      * Fetch all certs associated with this alias.
 707      */
 708     Certificate[] getCertificates(
 709                                     KeyStore keyStore, String aliases) {
 710 
 711         Vector<Certificate> vcerts = null;
 712 
 713         StringTokenizer st = new StringTokenizer(aliases, ",");
 714         int n = 0;
 715 
 716         while (st.hasMoreTokens()) {
 717             String alias = st.nextToken().trim();
 718             n++;
 719             Certificate cert = null;
 720             //See if this alias's cert has already been cached
 721             cert = (Certificate) aliasMapping.get(alias);
 722             if (cert == null && keyStore != null) {
 723 
 724                 try {
 725                     cert = keyStore.getCertificate(alias);
 726                 } catch (KeyStoreException kse) {
 727                     // never happens, because keystore has already been loaded
 728                     // when we call this
 729                 }
 730                 if (cert != null) {
 731                     aliasMapping.put(alias, cert);
 732                     aliasMapping.put(cert, alias);
 733                 }
 734             }
 735 
 736             if (cert != null) {
 737                 if (vcerts == null)
 738                     vcerts = new Vector<Certificate>();
 739                 vcerts.addElement(cert);
 740             }
 741         }
 742 
 743         // make sure n == vcerts.size, since we are doing a logical *and*
 744         if (vcerts != null && n == vcerts.size()) {
 745             Certificate[] certs = new Certificate[vcerts.size()];
 746             vcerts.copyInto(certs);
 747             return certs;
 748         } else {
 749             return null;
 750         }
 751     }
 752 
 753     /**
 754      * Enumerate all the entries in the global policy object.
 755      * This method is used by policy admin tools.   The tools
 756      * should use the Enumeration methods on the returned object
 757      * to fetch the elements sequentially.
 758      */
 759     private final synchronized Enumeration<PolicyEntry> elements(){
 760         return policyEntries.elements();
 761     }
 762 
 763     /**
 764      * Examines this <code>Policy</code> and returns the Permissions granted
 765      * to the specified <code>Subject</code> and <code>CodeSource</code>.
 766      *
 767      * <p> Permissions for a particular <i>grant</i> entry are returned
 768      * if the <code>CodeSource</code> constructed using the codebase and
 769      * signedby values specified in the entry <code>implies</code>
 770      * the <code>CodeSource</code> provided to this method, and if the
 771      * <code>Subject</code> provided to this method contains all of the
 772      * Principals specified in the entry.
 773      *
 774      * <p> The <code>Subject</code> provided to this method contains all
 775      * of the Principals specified in the entry if, for each
 776      * <code>Principal</code>, "P1", specified in the <i>grant</i> entry
 777      * one of the following two conditions is met:
 778      *
 779      * <p>
 780      * <ol>
 781      * <li> the <code>Subject</code> has a
 782      *      <code>Principal</code>, "P2", where
 783      *      <code>P2.getClass().getName()</code> equals the
 784      *      P1's class name, and where
 785      *      <code>P2.getName()</code> equals the P1's name.
 786      *
 787      * <li> P1 implements
 788      *      <code>com.sun.security.auth.PrincipalComparator</code>,
 789      *      and <code>P1.implies</code> the provided <code>Subject</code>.
 790      * </ol>
 791      *
 792      * <p> Note that this <code>Policy</code> implementation has
 793      * special handling for PrivateCredentialPermissions.
 794      * When this method encounters a <code>PrivateCredentialPermission</code>
 795      * which specifies "self" as the <code>Principal</code> class and name,
 796      * it does not add that <code>Permission</code> to the returned
 797      * <code>PermissionCollection</code>.  Instead, it builds
 798      * a new <code>PrivateCredentialPermission</code>
 799      * for each <code>Principal</code> associated with the provided
 800      * <code>Subject</code>.  Each new <code>PrivateCredentialPermission</code>
 801      * contains the same Credential class as specified in the
 802      * originally granted permission, as well as the Class and name
 803      * for the respective <code>Principal</code>.
 804      *
 805      * <p>
 806      *
 807      * @param subject the Permissions granted to this <code>Subject</code>
 808      *          and the additionally provided <code>CodeSource</code>
 809      *          are returned. <p>
 810      *
 811      * @param codesource the Permissions granted to this <code>CodeSource</code>
 812      *          and the additionally provided <code>Subject</code>
 813      *          are returned.
 814      *
 815      * @return the Permissions granted to the provided <code>Subject</code>
 816      *          <code>CodeSource</code>.
 817      */
 818     public PermissionCollection getPermissions(final Subject subject,
 819                                         final CodeSource codesource) {
 820 
 821         // XXX  when JAAS goes into the JDK core,
 822         //      we can remove this method and simply
 823         //      rely on the getPermissions variant that takes a codesource,
 824         //      which no one can use at this point in time.
 825         //      at that time, we can also make SubjectCodeSource a public
 826         //      class.
 827 
 828         // XXX
 829         //
 830         // 1)   if code instantiates PolicyFile directly, then it will need
 831         //      all the permissions required for the PolicyFile initialization
 832         // 2)   if code calls Policy.getPolicy, then it simply needs
 833         //      AuthPermission(getPolicy), and the javax.security.auth.Policy
 834         //      implementation instantiates PolicyFile in a doPrivileged block
 835         // 3)   if after instantiating a Policy (either via #1 or #2),
 836         //      code calls getPermissions, PolicyFile wraps the call
 837         //      in a doPrivileged block.
 838         return java.security.AccessController.doPrivileged
 839             (new java.security.PrivilegedAction<PermissionCollection>() {
 840             public PermissionCollection run() {
 841                 SubjectCodeSource scs = new SubjectCodeSource
 842                     (subject,
 843                     null,
 844                     codesource == null ? null : codesource.getLocation(),
 845                     codesource == null ? null : codesource.getCertificates());
 846                 if (initialized)
 847                     return getPermissions(new Permissions(), scs);
 848                 else
 849                     return new PolicyPermissions(PolicyFile.this, scs);
 850             }
 851         });
 852     }
 853 
 854     /**
 855      * Examines the global policy for the specified CodeSource, and
 856      * creates a PermissionCollection object with
 857      * the set of permissions for that principal's protection domain.
 858      *
 859      * @param CodeSource the codesource associated with the caller.
 860      * This encapsulates the original location of the code (where the code
 861      * came from) and the public key(s) of its signer.
 862      *
 863      * @return the set of permissions according to the policy.
 864      */
 865     PermissionCollection getPermissions(CodeSource codesource) {
 866 
 867         if (initialized)
 868             return getPermissions(new Permissions(), codesource);
 869         else
 870             return new PolicyPermissions(this, codesource);
 871     }
 872 
 873     /**
 874      * Examines the global policy for the specified CodeSource, and
 875      * creates a PermissionCollection object with
 876      * the set of permissions for that principal's protection domain.
 877      *
 878      * @param permissions the permissions to populate
 879      * @param codesource the codesource associated with the caller.
 880      * This encapsulates the original location of the code (where the code
 881      * came from) and the public key(s) of its signer.
 882      *
 883      * @return the set of permissions according to the policy.
 884      */
 885     Permissions getPermissions(final Permissions perms,
 886                                final CodeSource cs)
 887     {
 888         if (!initialized) {
 889             init();
 890         }
 891 
 892         final CodeSource codesource[] = {null};
 893 
 894         codesource[0] = canonicalizeCodebase(cs, true);
 895 
 896         if (debug != null) {
 897             debug.println("evaluate("+codesource[0]+")\n");
 898         }
 899 
 900         // needs to be in a begin/endPrivileged block because
 901         // codesource.implies calls URL.equals which does an
 902         // InetAddress lookup
 903 
 904         for (int i = 0; i < policyEntries.size(); i++) {
 905 
 906            PolicyEntry entry = policyEntries.elementAt(i);
 907 
 908            if (debug != null) {
 909                 debug.println("PolicyFile CodeSource implies: " +
 910                         entry.codesource.toString() + "\n\n" +
 911                         "\t" + codesource[0].toString() + "\n\n");
 912            }
 913 
 914            if (entry.codesource.implies(codesource[0])) {
 915                for (int j = 0; j < entry.permissions.size(); j++) {
 916                     Permission p = entry.permissions.elementAt(j);
 917                     if (debug != null) {
 918                        debug.println("  granting " + p);
 919                     }
 920                     if (!addSelfPermissions(p, entry.codesource,
 921                                         codesource[0], perms)) {
 922                         // we could check for duplicates
 923                         // before adding new permissions,
 924                         // but the SubjectDomainCombiner
 925                         // already checks for duplicates later
 926                         perms.add(p);
 927                     }
 928                 }
 929             }
 930         }
 931 
 932         // now see if any of the keys are trusted ids.
 933 
 934         if (!ignoreIdentityScope) {
 935             Certificate certs[] = codesource[0].getCertificates();
 936             if (certs != null) {
 937                 for (int k=0; k < certs.length; k++) {
 938                     if ((aliasMapping.get(certs[k]) == null) &&
 939                         checkForTrustedIdentity(certs[k])) {
 940                         // checkForTrustedIdentity added it
 941                         // to the policy for us. next time
 942                         // around we'll find it. This time
 943                         // around we need to add it.
 944                         perms.add(new java.security.AllPermission());
 945                     }
 946                 }
 947             }
 948         }
 949         return perms;
 950     }
 951 
 952     /**
 953      * Returns true if 'Self' permissions were added to the provided
 954      * 'perms', and false otherwise.
 955      *
 956      * <p>
 957      *
 958      * @param p check to see if this Permission is a "SELF"
 959      *                  PrivateCredentialPermission. <p>
 960      *
 961      * @param entryCs the codesource for the Policy entry.
 962      *
 963      * @param accCs the codesource for from the current AccessControlContext.
 964      *
 965      * @param perms the PermissionCollection where the individual
 966      *                  PrivateCredentialPermissions will be added.
 967      */
 968     private boolean addSelfPermissions(final Permission p,
 969                                 CodeSource entryCs,
 970                                 CodeSource accCs,
 971                                 Permissions perms) {
 972 
 973         if (!(p instanceof PrivateCredentialPermission))
 974             return false;
 975 
 976         if (!(entryCs instanceof SubjectCodeSource))
 977             return false;
 978 
 979 
 980         PrivateCredentialPermission pcp = (PrivateCredentialPermission)p;
 981         SubjectCodeSource scs = (SubjectCodeSource)entryCs;
 982 
 983         // see if it is a SELF permission
 984         String[][] pPrincipals = pcp.getPrincipals();
 985         if (pPrincipals.length <= 0 ||
 986             !pPrincipals[0][0].equalsIgnoreCase("self") ||
 987             !pPrincipals[0][1].equalsIgnoreCase("self")) {
 988 
 989             // regular PrivateCredentialPermission
 990             return false;
 991         } else {
 992 
 993             // granted a SELF permission - create a
 994             // PrivateCredentialPermission for each
 995             // of the Policy entry's CodeSource Principals
 996 
 997             if (scs.getPrincipals() == null) {
 998                 // XXX SubjectCodeSource has no Subject???
 999                 return true;
1000             }
1001 
1002             ListIterator<PolicyParser.PrincipalEntry> pli =
1003                                         scs.getPrincipals().listIterator();
1004             while (pli.hasNext()) {
1005 
1006                 PolicyParser.PrincipalEntry principal = pli.next();
1007 
1008                 // XXX
1009                 //      if the Policy entry's Principal does not contain a
1010                 //              WILDCARD for the Principal name, then a
1011                 //              new PrivateCredentialPermission is created
1012                 //              for the Principal listed in the Policy entry.
1013                 //      if the Policy entry's Principal contains a WILDCARD
1014                 //              for the Principal name, then a new
1015                 //              PrivateCredentialPermission is created
1016                 //              for each Principal associated with the Subject
1017                 //              in the current ACC.
1018 
1019                 String[][] principalInfo = getPrincipalInfo
1020                                                 (principal, accCs);
1021 
1022                 for (int i = 0; i < principalInfo.length; i++) {
1023 
1024                     // here's the new PrivateCredentialPermission
1025 
1026                     PrivateCredentialPermission newPcp =
1027                         new PrivateCredentialPermission
1028                                 (pcp.getCredentialClass() +
1029                                         " " +
1030                                         principalInfo[i][0] +
1031                                         " " +
1032                                         "\"" + principalInfo[i][1] + "\"",
1033                                 "read");
1034 
1035                     if (debug != null) {
1036                         debug.println("adding SELF permission: " +
1037                                         newPcp.toString());
1038                     }
1039 
1040                     perms.add(newPcp);
1041                 }
1042             }
1043         }
1044         return true;
1045     }
1046 
1047     /**
1048      * return the principal class/name pair in the 2D array.
1049      * array[x][y]:     x corresponds to the array length.
1050      *                  if (y == 0), it's the principal class.
1051      *                  if (y == 1), it's the principal name.
1052      */
1053     private String[][] getPrincipalInfo
1054                 (PolicyParser.PrincipalEntry principal,
1055                 final CodeSource accCs) {
1056 
1057         // there are 3 possibilities:
1058         // 1) the entry's Principal class and name are not wildcarded
1059         // 2) the entry's Principal name is wildcarded only
1060         // 3) the entry's Principal class and name are wildcarded
1061 
1062         if (!principal.principalClass.equals
1063                 (PolicyParser.PrincipalEntry.WILDCARD_CLASS) &&
1064             !principal.principalName.equals
1065                 (PolicyParser.PrincipalEntry.WILDCARD_NAME)) {
1066 
1067             // build a PrivateCredentialPermission for the principal
1068             // from the Policy entry
1069             String[][] info = new String[1][2];
1070             info[0][0] = principal.principalClass;
1071             info[0][1] = principal.principalName;
1072             return info;
1073 
1074         } else if (!principal.principalClass.equals
1075                 (PolicyParser.PrincipalEntry.WILDCARD_CLASS) &&
1076             principal.principalName.equals
1077                 (PolicyParser.PrincipalEntry.WILDCARD_NAME)) {
1078 
1079             // build a PrivateCredentialPermission for all
1080             // the Subject's principals that are instances of principalClass
1081 
1082             // the accCs is guaranteed to be a SubjectCodeSource
1083             // because the earlier CodeSource.implies succeeded
1084             SubjectCodeSource scs = (SubjectCodeSource)accCs;
1085 
1086             Set<? extends Principal> principalSet = null;
1087             try {
1088                 // principal.principalClass should extend Principal
1089                 // If it doesn't, we should stop here with a ClassCastException.
1090                 @SuppressWarnings("unchecked")
1091                 Class<? extends Principal> pClass = (Class<? extends Principal>)
1092                         Class.forName(principal.principalClass, false,
1093                                       ClassLoader.getSystemClassLoader());
1094                 principalSet = scs.getSubject().getPrincipals(pClass);
1095             } catch (Exception e) {
1096                 if (debug != null) {
1097                     debug.println("problem finding Principal Class " +
1098                                   "when expanding SELF permission: " +
1099                                   e.toString());
1100                 }
1101             }
1102 
1103             if (principalSet == null) {
1104                 // error
1105                 return new String[0][0];
1106             }
1107 
1108             String[][] info = new String[principalSet.size()][2];
1109 
1110             int i = 0;
1111             for (Principal p : principalSet) {
1112                 info[i][0] = p.getClass().getName();
1113                 info[i][1] = p.getName();
1114                 i++;
1115             }
1116             return info;
1117 
1118         } else {
1119 
1120             // build a PrivateCredentialPermission for every
1121             // one of the current Subject's principals
1122 
1123             // the accCs is guaranteed to be a SubjectCodeSource
1124             // because the earlier CodeSource.implies succeeded
1125             SubjectCodeSource scs = (SubjectCodeSource)accCs;
1126             Set<Principal> principalSet = scs.getSubject().getPrincipals();
1127 
1128             String[][] info = new String[principalSet.size()][2];
1129             java.util.Iterator<Principal> pIterator = principalSet.iterator();
1130 
1131             int i = 0;
1132             while (pIterator.hasNext()) {
1133                 Principal p = pIterator.next();
1134                 info[i][0] = p.getClass().getName();
1135                 info[i][1] = p.getName();
1136                 i++;
1137             }
1138             return info;
1139         }
1140     }
1141 
1142     /*
1143      * Returns the signer certificates from the list of certificates associated
1144      * with the given code source.
1145      *
1146      * The signer certificates are those certificates that were used to verify
1147      * signed code originating from the codesource location.
1148      *
1149      * This method assumes that in the given code source, each signer
1150      * certificate is followed by its supporting certificate chain
1151      * (which may be empty), and that the signer certificate and its
1152      * supporting certificate chain are ordered bottom-to-top (i.e., with the
1153      * signer certificate first and the (root) certificate authority last).
1154      */
1155     Certificate[] getSignerCertificates(CodeSource cs) {
1156         Certificate[] certs = null;
1157         if ((certs = cs.getCertificates()) == null)
1158             return null;
1159         for (int i=0; i<certs.length; i++) {
1160             if (!(certs[i] instanceof X509Certificate))
1161                 return cs.getCertificates();
1162         }
1163 
1164         // Do we have to do anything?
1165         int i = 0;
1166         int count = 0;
1167         while (i < certs.length) {
1168             count++;
1169             while (((i+1) < certs.length)
1170                    && ((X509Certificate)certs[i]).getIssuerDN().equals(
1171                            ((X509Certificate)certs[i+1]).getSubjectDN())) {
1172                 i++;
1173             }
1174             i++;
1175         }
1176         if (count == certs.length)
1177             // Done
1178             return certs;
1179 
1180         ArrayList<Certificate> userCertList = new ArrayList<>();
1181         i = 0;
1182         while (i < certs.length) {
1183             userCertList.add(certs[i]);
1184             while (((i+1) < certs.length)
1185                    && ((X509Certificate)certs[i]).getIssuerDN().equals(
1186                            ((X509Certificate)certs[i+1]).getSubjectDN())) {
1187                 i++;
1188             }
1189             i++;
1190         }
1191         Certificate[] userCerts = new Certificate[userCertList.size()];
1192         userCertList.toArray(userCerts);
1193         return userCerts;
1194     }
1195 
1196     private CodeSource canonicalizeCodebase(CodeSource cs,
1197                                             boolean extractSignerCerts) {
1198         CodeSource canonCs = cs;
1199         if (cs.getLocation() != null &&
1200             cs.getLocation().getProtocol().equalsIgnoreCase("file")) {
1201             try {
1202                 String path = cs.getLocation().getFile().replace
1203                                                         ('/',
1204                                                         File.separatorChar);
1205                 URL csUrl = null;
1206                 if (path.endsWith("*")) {
1207                     // remove trailing '*' because it causes canonicalization
1208                     // to fail on win32
1209                     path = path.substring(0, path.length()-1);
1210                     boolean appendFileSep = false;
1211                     if (path.endsWith(File.separator))
1212                         appendFileSep = true;
1213                     if (path.equals("")) {
1214                         path = System.getProperty("user.dir");
1215                     }
1216                     File f = new File(path);
1217                     path = f.getCanonicalPath();
1218                     StringBuffer sb = new StringBuffer(path);
1219                     // reappend '*' to canonicalized filename (note that
1220                     // canonicalization may have removed trailing file
1221                     // separator, so we have to check for that, too)
1222                     if (!path.endsWith(File.separator) &&
1223                         (appendFileSep || f.isDirectory()))
1224                         sb.append(File.separatorChar);
1225                     sb.append('*');
1226                     path = sb.toString();
1227                 } else {
1228                     path = new File(path).getCanonicalPath();
1229                 }
1230                 csUrl = new File(path).toURL();
1231 
1232                 if (cs instanceof SubjectCodeSource) {
1233                     SubjectCodeSource scs = (SubjectCodeSource)cs;
1234                     if (extractSignerCerts) {
1235                         canonCs = new SubjectCodeSource
1236                                                 (scs.getSubject(),
1237                                                 scs.getPrincipals(),
1238                                                 csUrl,
1239                                                 getSignerCertificates(scs));
1240                     } else {
1241                         canonCs = new SubjectCodeSource
1242                                                 (scs.getSubject(),
1243                                                 scs.getPrincipals(),
1244                                                 csUrl,
1245                                                 scs.getCertificates());
1246                     }
1247                 } else {
1248                     if (extractSignerCerts) {
1249                         canonCs = new CodeSource(csUrl,
1250                                                 getSignerCertificates(cs));
1251                     } else {
1252                         canonCs = new CodeSource(csUrl,
1253                                                 cs.getCertificates());
1254                     }
1255                 }
1256             } catch (IOException ioe) {
1257                 // leave codesource as it is, unless we have to extract its
1258                 // signer certificates
1259                 if (extractSignerCerts) {
1260                     if (!(cs instanceof SubjectCodeSource)) {
1261                         canonCs = new CodeSource(cs.getLocation(),
1262                                                 getSignerCertificates(cs));
1263                     } else {
1264                         SubjectCodeSource scs = (SubjectCodeSource)cs;
1265                         canonCs = new SubjectCodeSource(scs.getSubject(),
1266                                                 scs.getPrincipals(),
1267                                                 scs.getLocation(),
1268                                                 getSignerCertificates(scs));
1269                     }
1270                 }
1271             }
1272         } else {
1273             if (extractSignerCerts) {
1274                 if (!(cs instanceof SubjectCodeSource)) {
1275                     canonCs = new CodeSource(cs.getLocation(),
1276                                         getSignerCertificates(cs));
1277                 } else {
1278                     SubjectCodeSource scs = (SubjectCodeSource)cs;
1279                     canonCs = new SubjectCodeSource(scs.getSubject(),
1280                                         scs.getPrincipals(),
1281                                         scs.getLocation(),
1282                                         getSignerCertificates(scs));
1283                 }
1284             }
1285         }
1286         return canonCs;
1287     }
1288 
1289     /**
1290      * Each entry in the policy configuration file is represented by a
1291      * PolicyEntry object.  <p>
1292      *
1293      * A PolicyEntry is a (CodeSource,Permission) pair.  The
1294      * CodeSource contains the (URL, PublicKey) that together identify
1295      * where the Java bytecodes come from and who (if anyone) signed
1296      * them.  The URL could refer to localhost.  The URL could also be
1297      * null, meaning that this policy entry is given to all comers, as
1298      * long as they match the signer field.  The signer could be null,
1299      * meaning the code is not signed. <p>
1300      *
1301      * The Permission contains the (Type, Name, Action) triplet. <p>
1302      *
1303      * For now, the Policy object retrieves the public key from the
1304      * X.509 certificate on disk that corresponds to the signedBy
1305      * alias specified in the Policy config file.  For reasons of
1306      * efficiency, the Policy object keeps a hashtable of certs already
1307      * read in.  This could be replaced by a secure internal key
1308      * store.
1309      *
1310      * <p>
1311      * For example, the entry
1312      * <pre>
1313      *          permission java.io.File "/tmp", "read,write",
1314      *          signedBy "Duke";
1315      * </pre>
1316      * is represented internally
1317      * <pre>
1318      *
1319      * FilePermission f = new FilePermission("/tmp", "read,write");
1320      * PublicKey p = publickeys.get("Duke");
1321      * URL u = InetAddress.getLocalHost();
1322      * CodeBase c = new CodeBase( p, u );
1323      * pe = new PolicyEntry(f, c);
1324      * </pre>
1325      *
1326      * @author Marianne Mueller
1327      * @author Roland Schemers
1328      * @see java.security.CodeSource
1329      * @see java.security.Policy
1330      * @see java.security.Permissions
1331      * @see java.security.ProtectionDomain
1332      */
1333 
1334     private static class PolicyEntry {
1335 
1336         CodeSource codesource;
1337         Vector<Permission> permissions;
1338 
1339         /**
1340          * Given a Permission and a CodeSource, create a policy entry.
1341          *
1342          * XXX Decide if/how to add validity fields and "purpose" fields to
1343          * XXX policy entries
1344          *
1345          * @param cs the CodeSource, which encapsulates the URL and the public
1346          *        key
1347          *        attributes from the policy config file.   Validity checks are
1348          *        performed on the public key before PolicyEntry is called.
1349          *
1350          */
1351         PolicyEntry(CodeSource cs)
1352         {
1353             this.codesource = cs;
1354             this.permissions = new Vector<Permission>();
1355         }
1356 
1357         /**
1358          * add a Permission object to this entry.
1359          */
1360         void add(Permission p) {
1361             permissions.addElement(p);
1362         }
1363 
1364         /**
1365          * Return the CodeSource for this policy entry
1366          */
1367         CodeSource getCodeSource() {
1368             return this.codesource;
1369         }
1370 
1371         public String toString(){
1372             StringBuffer sb = new StringBuffer();
1373             sb.append(rb.getString("LPARAM"));
1374             sb.append(getCodeSource());
1375             sb.append("\n");
1376             for (int j = 0; j < permissions.size(); j++) {
1377                 Permission p = permissions.elementAt(j);
1378                 sb.append(rb.getString("SPACE"));
1379                 sb.append(rb.getString("SPACE"));
1380                 sb.append(p);
1381                 sb.append(rb.getString("NEWLINE"));
1382             }
1383             sb.append(rb.getString("RPARAM"));
1384             sb.append(rb.getString("NEWLINE"));
1385             return sb.toString();
1386         }
1387 
1388     }
1389 }
1390 
1391 class PolicyPermissions extends PermissionCollection {
1392 
1393     private static final long serialVersionUID = -1954188373270545523L;
1394 
1395     private CodeSource codesource;
1396     private Permissions perms;
1397     private PolicyFile policy;
1398     private boolean notInit; // have we pulled in the policy permissions yet?
1399     private Vector<Permission> additionalPerms;
1400 
1401     PolicyPermissions(PolicyFile policy,
1402                       CodeSource codesource)
1403     {
1404         this.codesource = codesource;
1405         this.policy = policy;
1406         this.perms = null;
1407         this.notInit = true;
1408         this.additionalPerms = null;
1409     }
1410 
1411     public void add(Permission permission) {
1412         if (isReadOnly())
1413             throw new SecurityException
1414             (PolicyFile.rb.getString
1415             ("attempt.to.add.a.Permission.to.a.readonly.PermissionCollection"));
1416 
1417         if (perms == null) {
1418             if (additionalPerms == null)
1419                 additionalPerms = new Vector<Permission>();
1420             additionalPerms.add(permission);
1421         } else {
1422             perms.add(permission);
1423         }
1424     }
1425 
1426     private synchronized void init() {
1427         if (notInit) {
1428             if (perms == null)
1429                 perms = new Permissions();
1430 
1431             if (additionalPerms != null) {
1432                 Enumeration<Permission> e = additionalPerms.elements();
1433                 while (e.hasMoreElements()) {
1434                     perms.add(e.nextElement());
1435                 }
1436                 additionalPerms = null;
1437             }
1438             policy.getPermissions(perms,codesource);
1439             notInit=false;
1440         }
1441     }
1442 
1443     public boolean implies(Permission permission) {
1444         if (notInit)
1445             init();
1446         return perms.implies(permission);
1447     }
1448 
1449     public Enumeration<Permission> elements() {
1450         if (notInit)
1451             init();
1452         return perms.elements();
1453     }
1454 
1455     public String toString() {
1456         if (notInit)
1457             init();
1458         return perms.toString();
1459     }
1460 }