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