1 /*
   2  * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.security.provider;
  27 
  28 import java.io.*;
  29 import java.lang.reflect.*;
  30 import java.net.URL;
  31 import java.util.*;
  32 
  33 import java.security.AccessController;
  34 import java.security.CodeSource;
  35 import java.security.KeyStore;
  36 import java.security.KeyStoreException;
  37 import java.security.Permission;
  38 import java.security.Permissions;
  39 import java.security.PermissionCollection;
  40 import java.security.Principal;
  41 import java.security.PrivilegedAction;
  42 import java.security.UnresolvedPermission;
  43 import java.security.Security;
  44 import java.security.cert.Certificate;
  45 import java.security.cert.X509Certificate;
  46 
  47 import javax.security.auth.Subject;
  48 import javax.security.auth.PrivateCredentialPermission;
  49 
  50 import sun.security.provider.PolicyParser.GrantEntry;
  51 import sun.security.provider.PolicyParser.PermissionEntry;
  52 import sun.security.provider.PolicyParser.PrincipalEntry;
  53 import sun.security.util.Debug;
  54 import sun.security.util.PolicyUtil;
  55 import sun.security.util.PropertyExpander;
  56 
  57 /**
  58  * See {@code com.sun.security.auth.PolicyFile} for the class description.
  59  * This class is necessary in order to support a default
  60  * {@code javax.security.auth.Policy} implementation on the compact1 and
  61  * compact2 profiles.
  62  *
  63  * @deprecated As of JDK 1.4, replaced by
  64  *             {@code sun.security.provider.PolicyFile}.
  65  *             This class is entirely deprecated.
  66  */
  67 @Deprecated
  68 @SuppressWarnings("removal")
  69 public class AuthPolicyFile extends javax.security.auth.Policy {
  70 
  71     static final ResourceBundle rb =
  72         AccessController.doPrivileged(new PrivilegedAction<ResourceBundle>() {
  73             @Override public ResourceBundle run() {
  74                 return (ResourceBundle.getBundle
  75                         ("sun.security.util.AuthResources"));
  76             }
  77         });
  78 
  79     private static final Debug debug = Debug.getInstance("policy",
  80                                                          "\t[Auth Policy]");
  81 
  82     private static final String AUTH_POLICY = "java.security.auth.policy";
  83     private static final String SECURITY_MANAGER = "java.security.manager";
  84     private static final String AUTH_POLICY_URL = "auth.policy.url.";
  85 
  86     private Vector<PolicyEntry> policyEntries;
  87     private Hashtable<Object, Object> aliasMapping;
  88 
  89     private boolean initialized = false;
  90 
  91     private boolean expandProperties = true;
  92     private boolean ignoreIdentityScope = true;
  93 
  94     // for use with the reflection API
  95     private static final Class<?>[] PARAMS = { String.class, String.class};
  96 
  97     /**
  98      * Initializes the Policy object and reads the default policy
  99      * configuration file(s) into the Policy object.
 100      */
 101     public AuthPolicyFile() {
 102         // initialize Policy if either the AUTH_POLICY or
 103         // SECURITY_MANAGER properties are set
 104         String prop = System.getProperty(AUTH_POLICY);
 105 
 106         if (prop == null) {
 107             prop = System.getProperty(SECURITY_MANAGER);
 108         }
 109         if (prop != null) {
 110             init();
 111         }
 112     }
 113 
 114     private synchronized void init() {
 115         if (initialized) {
 116             return;
 117         }
 118 
 119         policyEntries = new Vector<PolicyEntry>();
 120         aliasMapping = new Hashtable<Object, Object>(11);
 121 
 122         initPolicyFile();
 123         initialized = true;
 124     }
 125 
 126     @Override
 127     public synchronized void refresh() {
 128 
 129         java.lang.SecurityManager sm = System.getSecurityManager();
 130         if (sm != null) {
 131             sm.checkPermission(new javax.security.auth.AuthPermission
 132                                 ("refreshPolicy"));
 133         }
 134 
 135         // XXX
 136         //
 137         // 1)   if code instantiates PolicyFile directly, then it will need
 138         //      all the permissions required for the PolicyFile initialization
 139         // 2)   if code calls Policy.getPolicy, then it simply needs
 140         //      AuthPermission(getPolicy), and the javax.security.auth.Policy
 141         //      implementation instantiates PolicyFile in a doPrivileged block
 142         // 3)   if after instantiating a Policy (either via #1 or #2),
 143         //      code calls refresh, it simply needs
 144         //      AuthPermission(refreshPolicy).  then PolicyFile wraps
 145         //      the refresh in a doPrivileged block.
 146         initialized = false;
 147         AccessController.doPrivileged(new PrivilegedAction<Void>() {
 148             @Override public Void run() {
 149                 init();
 150                 return null;
 151             }
 152         });
 153     }
 154 
 155     private KeyStore initKeyStore(URL policyUrl, String keyStoreName,
 156                                   String keyStoreType) {
 157         if (keyStoreName != null) {
 158             try {
 159                 /*
 160                  * location of keystore is specified as absolute URL in policy
 161                  * file, or is relative to URL of policy file
 162                  */
 163                 URL keyStoreUrl = null;
 164                 try {
 165                     keyStoreUrl = new URL(keyStoreName);
 166                     // absolute URL
 167                 } catch (java.net.MalformedURLException e) {
 168                     // relative URL
 169                     keyStoreUrl = new URL(policyUrl, keyStoreName);
 170                 }
 171 
 172                 if (debug != null) {
 173                     debug.println("reading keystore"+keyStoreUrl);
 174                 }
 175 
 176                 InputStream inStream = new BufferedInputStream(
 177                     PolicyUtil.getInputStream(keyStoreUrl));
 178 
 179                 KeyStore ks;
 180                 if (keyStoreType != null)
 181                     ks = KeyStore.getInstance(keyStoreType);
 182                 else
 183                     ks = KeyStore.getInstance(KeyStore.getDefaultType());
 184                 ks.load(inStream, null);
 185                 inStream.close();
 186                 return ks;
 187             } catch (Exception e) {
 188                 // ignore, treat it like we have no keystore
 189                 if (debug != null) {
 190                     debug.println("Debug info only. No keystore.");
 191                     e.printStackTrace();
 192                 }
 193                 return null;
 194             }
 195         }
 196         return null;
 197     }
 198 
 199     private void initPolicyFile() {
 200 
 201         String prop = Security.getProperty("policy.expandProperties");
 202         if (prop != null) {
 203             expandProperties = prop.equalsIgnoreCase("true");
 204         }
 205 
 206         String iscp = Security.getProperty("policy.ignoreIdentityScope");
 207         if (iscp != null) {
 208             ignoreIdentityScope = iscp.equalsIgnoreCase("true");
 209         }
 210 
 211         String allowSys = Security.getProperty("policy.allowSystemProperty");
 212         if (allowSys != null && allowSys.equalsIgnoreCase("true")) {
 213             String extra_policy = System.getProperty(AUTH_POLICY);
 214             if (extra_policy != null) {
 215                 boolean overrideAll = false;
 216                 if (extra_policy.startsWith("=")) {
 217                     overrideAll = true;
 218                     extra_policy = extra_policy.substring(1);
 219                 }
 220                 try {
 221                     extra_policy = PropertyExpander.expand(extra_policy);
 222                     URL policyURL;
 223                     File policyFile = new File(extra_policy);
 224                     if (policyFile.exists()) {
 225                         policyURL =
 226                             new URL("file:" + policyFile.getCanonicalPath());
 227                     } else {
 228                         policyURL = new URL(extra_policy);
 229                     }
 230                     if (debug != null) {
 231                         debug.println("reading " + policyURL);
 232                     }
 233                     init(policyURL);
 234                 } catch (Exception e) {
 235                     // ignore.
 236                     if (debug != null) {
 237                         debug.println("caught exception: " + e);
 238                     }
 239 
 240                 }
 241                 if (overrideAll) {
 242                     if (debug != null) {
 243                         debug.println("overriding other policies!");
 244                     }
 245                     return;
 246                 }
 247             }
 248         }
 249 
 250         int n = 1;
 251         boolean loaded_one = false;
 252         String policy_url;
 253 
 254         while ((policy_url = Security.getProperty(AUTH_POLICY_URL+n)) != null) {
 255             try {
 256                 policy_url = PropertyExpander.expand(policy_url).replace
 257                                                 (File.separatorChar, '/');
 258                 if (debug != null) {
 259                     debug.println("reading " + policy_url);
 260                 }
 261                 init(new URL(policy_url));
 262                 loaded_one = true;
 263             } catch (Exception e) {
 264                 if (debug != null) {
 265                     debug.println("Debug info only. Error reading policy " + e);
 266                     e.printStackTrace();
 267                 }
 268                 // ignore that policy
 269             }
 270             n++;
 271         }
 272 
 273         if (loaded_one == false) {
 274             // do not load a static policy
 275         }
 276     }
 277 
 278     /**
 279      * Checks public key. If it is marked as trusted in
 280      * the identity database, add it to the policy
 281      * with the AllPermission.
 282      */
 283     private boolean checkForTrustedIdentity(final Certificate cert) {
 284         return false;
 285     }
 286 
 287     /**
 288      * Reads a policy configuration into the Policy object using a
 289      * Reader object.
 290      *
 291      * @param policyFile the policy Reader object.
 292      */
 293     private void init(URL policy) {
 294         PolicyParser pp = new PolicyParser(expandProperties);
 295         try (InputStreamReader isr
 296                 = new InputStreamReader(PolicyUtil.getInputStream(policy))) {
 297             pp.read(isr);
 298             KeyStore keyStore = initKeyStore(policy, pp.getKeyStoreUrl(),
 299                                              pp.getKeyStoreType());
 300             Enumeration<GrantEntry> enum_ = pp.grantElements();
 301             while (enum_.hasMoreElements()) {
 302                 GrantEntry ge = enum_.nextElement();
 303                 addGrantEntry(ge, keyStore);
 304             }
 305         } catch (PolicyParser.ParsingException pe) {
 306             System.err.println(AUTH_POLICY +
 307                                rb.getString(".error.parsing.") + policy);
 308             System.err.println(AUTH_POLICY + rb.getString("COLON") +
 309                                pe.getMessage());
 310             if (debug != null) {
 311                 pe.printStackTrace();
 312             }
 313         } catch (Exception e) {
 314             if (debug != null) {
 315                 debug.println("error parsing " + policy);
 316                 debug.println(e.toString());
 317                 e.printStackTrace();
 318             }
 319         }
 320     }
 321 
 322     /**
 323      * Given a PermissionEntry, create a codeSource.
 324      *
 325      * @return null if signedBy alias is not recognized
 326      */
 327     CodeSource getCodeSource(GrantEntry ge, KeyStore keyStore)
 328             throws java.net.MalformedURLException
 329     {
 330         Certificate[] certs = null;
 331         if (ge.signedBy != null) {
 332             certs = getCertificates(keyStore, ge.signedBy);
 333             if (certs == null) {
 334                 // we don't have a key for this alias,
 335                 // just return
 336                 if (debug != null) {
 337                     debug.println(" no certs for alias " +
 338                                        ge.signedBy + ", ignoring.");
 339                 }
 340                 return null;
 341             }
 342         }
 343 
 344         URL location;
 345         if (ge.codeBase != null) {
 346             location = new URL(ge.codeBase);
 347         } else {
 348             location = null;
 349         }
 350 
 351         if (ge.principals == null || ge.principals.size() == 0) {
 352             return (canonicalizeCodebase
 353                         (new CodeSource(location, certs),
 354                         false));
 355         } else {
 356             return (canonicalizeCodebase
 357                 (new SubjectCodeSource(null, ge.principals, location, certs),
 358                 false));
 359         }
 360     }
 361 
 362     /**
 363      * Add one policy entry to the vector.
 364      */
 365     private void addGrantEntry(GrantEntry ge, KeyStore keyStore) {
 366 
 367         if (debug != null) {
 368             debug.println("Adding policy entry: ");
 369             debug.println("  signedBy " + ge.signedBy);
 370             debug.println("  codeBase " + ge.codeBase);
 371             if (ge.principals != null) {
 372                 for (PrincipalEntry pppe : ge.principals) {
 373                     debug.println("  " + pppe.getPrincipalClass() +
 374                                         " " + pppe.getPrincipalName());
 375                 }
 376             }
 377             debug.println();
 378         }
 379 
 380         try {
 381             CodeSource codesource = getCodeSource(ge, keyStore);
 382             // skip if signedBy alias was unknown...
 383             if (codesource == null) return;
 384 
 385             PolicyEntry entry = new PolicyEntry(codesource);
 386             Enumeration<PermissionEntry> enum_ = ge.permissionElements();
 387             while (enum_.hasMoreElements()) {
 388                 PermissionEntry pe = enum_.nextElement();
 389                 try {
 390                     // XXX special case PrivateCredentialPermission-SELF
 391                     Permission perm;
 392                     if (pe.permission.equals
 393                         ("javax.security.auth.PrivateCredentialPermission") &&
 394                         pe.name.endsWith(" self")) {
 395                         perm = getInstance(pe.permission,
 396                                          pe.name + " \"self\"",
 397                                          pe.action);
 398                     } else {
 399                         perm = getInstance(pe.permission,
 400                                          pe.name,
 401                                          pe.action);
 402                     }
 403                     entry.add(perm);
 404                     if (debug != null) {
 405                         debug.println("  "+perm);
 406                     }
 407                 } catch (ClassNotFoundException cnfe) {
 408                     Certificate[] certs;
 409                     if (pe.signedBy != null) {
 410                         certs = getCertificates(keyStore, pe.signedBy);
 411                     } else {
 412                         certs = null;
 413                     }
 414 
 415                     // only add if we had no signer or we had
 416                     // a signer and found the keys for it.
 417                     if (certs != null || pe.signedBy == null) {
 418                             Permission perm = new UnresolvedPermission(
 419                                              pe.permission,
 420                                              pe.name,
 421                                              pe.action,
 422                                              certs);
 423                             entry.add(perm);
 424                             if (debug != null) {
 425                                 debug.println("  "+perm);
 426                             }
 427                     }
 428                 } catch (java.lang.reflect.InvocationTargetException ite) {
 429                     System.err.println
 430                         (AUTH_POLICY +
 431                         rb.getString(".error.adding.Permission.") +
 432                         pe.permission +
 433                         rb.getString("SPACE") +
 434                         ite.getTargetException());
 435                 } catch (Exception e) {
 436                     System.err.println
 437                         (AUTH_POLICY +
 438                         rb.getString(".error.adding.Permission.") +
 439                         pe.permission +
 440                         rb.getString("SPACE") +
 441                         e);
 442                 }
 443             }
 444             policyEntries.addElement(entry);
 445         } catch (Exception e) {
 446             System.err.println
 447                 (AUTH_POLICY +
 448                 rb.getString(".error.adding.Entry.") +
 449                 ge +
 450                 rb.getString("SPACE") +
 451                 e);
 452         }
 453 
 454         if (debug != null) {
 455             debug.println();
 456         }
 457     }
 458 
 459     /**
 460      * Returns a new Permission object of the given Type. The Permission is
 461      * created by getting the
 462      * Class object using the <code>Class.forName</code> method, and using
 463      * the reflection API to invoke the (String name, String actions)
 464      * constructor on the
 465      * object.
 466      *
 467      * @param type the type of Permission being created.
 468      * @param name the name of the Permission being created.
 469      * @param actions the actions of the Permission being created.
 470      *
 471      * @exception  ClassNotFoundException  if the particular Permission
 472      *             class could not be found.
 473      *
 474      * @exception  IllegalAccessException  if the class or initializer is
 475      *               not accessible.
 476      *
 477      * @exception  InstantiationException  if getInstance tries to
 478      *               instantiate an abstract class or an interface, or if the
 479      *               instantiation fails for some other reason.
 480      *
 481      * @exception  NoSuchMethodException if the (String, String) constructor
 482      *               is not found.
 483      *
 484      * @exception  InvocationTargetException if the underlying Permission
 485      *               constructor throws an exception.
 486      *
 487      */
 488     private static final Permission getInstance(String type,
 489                                     String name,
 490                                     String actions)
 491         throws ClassNotFoundException,
 492                InstantiationException,
 493                IllegalAccessException,
 494                NoSuchMethodException,
 495                InvocationTargetException
 496     {
 497         //XXX we might want to keep a hash of created factories...
 498         Class<?> pc = Class.forName(type);
 499         Constructor<?> c = pc.getConstructor(PARAMS);
 500         return (Permission) c.newInstance(new Object[] { name, actions });
 501     }
 502 
 503     /**
 504      * Fetch all certs associated with this alias.
 505      */
 506     Certificate[] getCertificates(KeyStore keyStore, String aliases) {
 507 
 508         Vector<Certificate> vcerts = null;
 509 
 510         StringTokenizer st = new StringTokenizer(aliases, ",");
 511         int n = 0;
 512 
 513         while (st.hasMoreTokens()) {
 514             String alias = st.nextToken().trim();
 515             n++;
 516             Certificate cert = null;
 517             // See if this alias's cert has already been cached
 518             cert = (Certificate) aliasMapping.get(alias);
 519             if (cert == null && keyStore != null) {
 520 
 521                 try {
 522                     cert = keyStore.getCertificate(alias);
 523                 } catch (KeyStoreException kse) {
 524                     // never happens, because keystore has already been loaded
 525                     // when we call this
 526                 }
 527                 if (cert != null) {
 528                     aliasMapping.put(alias, cert);
 529                     aliasMapping.put(cert, alias);
 530                 }
 531             }
 532 
 533             if (cert != null) {
 534                 if (vcerts == null) {
 535                     vcerts = new Vector<Certificate>();
 536                 }
 537                 vcerts.addElement(cert);
 538             }
 539         }
 540 
 541         // make sure n == vcerts.size, since we are doing a logical *and*
 542         if (vcerts != null && n == vcerts.size()) {
 543             Certificate[] certs = new Certificate[vcerts.size()];
 544             vcerts.copyInto(certs);
 545             return certs;
 546         } else {
 547             return null;
 548         }
 549     }
 550 
 551     /**
 552      * Enumerate all the entries in the global policy object.
 553      * This method is used by policy admin tools.   The tools
 554      * should use the Enumeration methods on the returned object
 555      * to fetch the elements sequentially.
 556      */
 557     private final synchronized Enumeration<PolicyEntry> elements() {
 558         return policyEntries.elements();
 559     }
 560 
 561     @Override
 562     public PermissionCollection getPermissions(final Subject subject,
 563                                                final CodeSource codesource) {
 564 
 565         // 1)   if code instantiates PolicyFile directly, then it will need
 566         //      all the permissions required for the PolicyFile initialization
 567         // 2)   if code calls Policy.getPolicy, then it simply needs
 568         //      AuthPermission(getPolicy), and the javax.security.auth.Policy
 569         //      implementation instantiates PolicyFile in a doPrivileged block
 570         // 3)   if after instantiating a Policy (either via #1 or #2),
 571         //      code calls getPermissions, PolicyFile wraps the call
 572         //      in a doPrivileged block.
 573         return AccessController.doPrivileged
 574             (new PrivilegedAction<PermissionCollection>() {
 575             @Override public PermissionCollection run() {
 576                 SubjectCodeSource scs = new SubjectCodeSource(
 577                     subject, null,
 578                     codesource == null ? null : codesource.getLocation(),
 579                     codesource == null ? null : codesource.getCertificates());
 580                 if (initialized) {
 581                     return getPermissions(new Permissions(), scs);
 582                 } else {
 583                     return new PolicyPermissions(AuthPolicyFile.this, scs);
 584                 }
 585             }
 586         });
 587     }
 588 
 589     /**
 590      * Examines the global policy for the specified CodeSource, and
 591      * creates a PermissionCollection object with
 592      * the set of permissions for that principal's protection domain.
 593      *
 594      * @param CodeSource the codesource associated with the caller.
 595      * This encapsulates the original location of the code (where the code
 596      * came from) and the public key(s) of its signer.
 597      *
 598      * @return the set of permissions according to the policy.
 599      */
 600     PermissionCollection getPermissions(CodeSource codesource) {
 601 
 602         if (initialized) {
 603             return getPermissions(new Permissions(), codesource);
 604         } else {
 605             return new PolicyPermissions(this, codesource);
 606         }
 607     }
 608 
 609     /**
 610      * Examines the global policy for the specified CodeSource, and
 611      * creates a PermissionCollection object with
 612      * the set of permissions for that principal's protection domain.
 613      *
 614      * @param permissions the permissions to populate
 615      * @param codesource the codesource associated with the caller.
 616      * This encapsulates the original location of the code (where the code
 617      * came from) and the public key(s) of its signer.
 618      *
 619      * @return the set of permissions according to the policy.
 620      */
 621     Permissions getPermissions(final Permissions perms,
 622                                final CodeSource cs)
 623     {
 624         if (!initialized) {
 625             init();
 626         }
 627 
 628         final CodeSource[] codesource = {null};
 629 
 630         codesource[0] = canonicalizeCodebase(cs, true);
 631 
 632         if (debug != null) {
 633             debug.println("evaluate(" + codesource[0] + ")\n");
 634         }
 635 
 636         // needs to be in a begin/endPrivileged block because
 637         // codesource.implies calls URL.equals which does an
 638         // InetAddress lookup
 639 
 640         for (int i = 0; i < policyEntries.size(); i++) {
 641 
 642            PolicyEntry entry = policyEntries.elementAt(i);
 643 
 644            if (debug != null) {
 645                 debug.println("PolicyFile CodeSource implies: " +
 646                               entry.codesource.toString() + "\n\n" +
 647                               "\t" + codesource[0].toString() + "\n\n");
 648            }
 649 
 650            if (entry.codesource.implies(codesource[0])) {
 651                for (int j = 0; j < entry.permissions.size(); j++) {
 652                     Permission p = entry.permissions.elementAt(j);
 653                     if (debug != null) {
 654                         debug.println("  granting " + p);
 655                     }
 656                     if (!addSelfPermissions(p, entry.codesource,
 657                                             codesource[0], perms)) {
 658                         // we could check for duplicates
 659                         // before adding new permissions,
 660                         // but the SubjectDomainCombiner
 661                         // already checks for duplicates later
 662                         perms.add(p);
 663                     }
 664                 }
 665             }
 666         }
 667 
 668         // now see if any of the keys are trusted ids.
 669 
 670         if (!ignoreIdentityScope) {
 671             Certificate[] certs = codesource[0].getCertificates();
 672             if (certs != null) {
 673                 for (int k=0; k < certs.length; k++) {
 674                     if (aliasMapping.get(certs[k]) == null &&
 675                         checkForTrustedIdentity(certs[k])) {
 676                         // checkForTrustedIdentity added it
 677                         // to the policy for us. next time
 678                         // around we'll find it. This time
 679                         // around we need to add it.
 680                         perms.add(new java.security.AllPermission());
 681                     }
 682                 }
 683             }
 684         }
 685         return perms;
 686     }
 687 
 688     /**
 689      * Returns true if 'Self' permissions were added to the provided
 690      * 'perms', and false otherwise.
 691      *
 692      * <p>
 693      *
 694      * @param p check to see if this Permission is a "SELF"
 695      *                  PrivateCredentialPermission. <p>
 696      *
 697      * @param entryCs the codesource for the Policy entry.
 698      *
 699      * @param accCs the codesource for from the current AccessControlContext.
 700      *
 701      * @param perms the PermissionCollection where the individual
 702      *                  PrivateCredentialPermissions will be added.
 703      */
 704     private boolean addSelfPermissions(final Permission p,
 705                                        CodeSource entryCs,
 706                                        CodeSource accCs,
 707                                        Permissions perms) {
 708 
 709         if (!(p instanceof PrivateCredentialPermission)) {
 710             return false;
 711         }
 712 
 713         if (!(entryCs instanceof SubjectCodeSource)) {
 714             return false;
 715         }
 716 
 717         PrivateCredentialPermission pcp = (PrivateCredentialPermission)p;
 718         SubjectCodeSource scs = (SubjectCodeSource)entryCs;
 719 
 720         // see if it is a SELF permission
 721         String[][] pPrincipals = pcp.getPrincipals();
 722         if (pPrincipals.length <= 0 ||
 723             !pPrincipals[0][0].equalsIgnoreCase("self") ||
 724             !pPrincipals[0][1].equalsIgnoreCase("self")) {
 725 
 726             // regular PrivateCredentialPermission
 727             return false;
 728         } else {
 729 
 730             // granted a SELF permission - create a
 731             // PrivateCredentialPermission for each
 732             // of the Policy entry's CodeSource Principals
 733 
 734             if (scs.getPrincipals() == null) {
 735                 // XXX SubjectCodeSource has no Subject???
 736                 return true;
 737             }
 738 
 739             for (PrincipalEntry principal : scs.getPrincipals()) {
 740 
 741                 //      if the Policy entry's Principal does not contain a
 742                 //              WILDCARD for the Principal name, then a
 743                 //              new PrivateCredentialPermission is created
 744                 //              for the Principal listed in the Policy entry.
 745                 //      if the Policy entry's Principal contains a WILDCARD
 746                 //              for the Principal name, then a new
 747                 //              PrivateCredentialPermission is created
 748                 //              for each Principal associated with the Subject
 749                 //              in the current ACC.
 750 
 751                 String[][] principalInfo = getPrincipalInfo(principal, accCs);
 752 
 753                 for (int i = 0; i < principalInfo.length; i++) {
 754 
 755                     // here's the new PrivateCredentialPermission
 756 
 757                     PrivateCredentialPermission newPcp =
 758                         new PrivateCredentialPermission
 759                                 (pcp.getCredentialClass() +
 760                                         " " +
 761                                         principalInfo[i][0] +
 762                                         " " +
 763                                         "\"" + principalInfo[i][1] + "\"",
 764                                 "read");
 765 
 766                     if (debug != null) {
 767                         debug.println("adding SELF permission: " +
 768                                         newPcp.toString());
 769                     }
 770 
 771                     perms.add(newPcp);
 772                 }
 773             }
 774         }
 775         return true;
 776     }
 777 
 778     /**
 779      * return the principal class/name pair in the 2D array.
 780      * array[x][y]:     x corresponds to the array length.
 781      *                  if (y == 0), it's the principal class.
 782      *                  if (y == 1), it's the principal name.
 783      */
 784     private String[][] getPrincipalInfo(PrincipalEntry principal,
 785                                         final CodeSource accCs) {
 786 
 787         // there are 3 possibilities:
 788         // 1) the entry's Principal class and name are not wildcarded
 789         // 2) the entry's Principal name is wildcarded only
 790         // 3) the entry's Principal class and name are wildcarded
 791 
 792         if (!principal.getPrincipalClass().equals
 793                 (PrincipalEntry.WILDCARD_CLASS) &&
 794             !principal.getPrincipalName().equals
 795                 (PrincipalEntry.WILDCARD_NAME)) {
 796 
 797             // build a PrivateCredentialPermission for the principal
 798             // from the Policy entry
 799             String[][] info = new String[1][2];
 800             info[0][0] = principal.getPrincipalClass();
 801             info[0][1] = principal.getPrincipalName();
 802             return info;
 803 
 804         } else if (!principal.getPrincipalClass().equals
 805                 (PrincipalEntry.WILDCARD_CLASS) &&
 806             principal.getPrincipalName().equals
 807                 (PrincipalEntry.WILDCARD_NAME)) {
 808 
 809             // build a PrivateCredentialPermission for all
 810             // the Subject's principals that are instances of principalClass
 811 
 812             // the accCs is guaranteed to be a SubjectCodeSource
 813             // because the earlier CodeSource.implies succeeded
 814             SubjectCodeSource scs = (SubjectCodeSource)accCs;
 815 
 816             Set<? extends Principal> principalSet = null;
 817             try {
 818                 // principal.principalClass should extend Principal
 819                 // If it doesn't, we should stop here with a ClassCastException.
 820                 @SuppressWarnings("unchecked")
 821                 Class<? extends Principal> pClass = (Class<? extends Principal>)
 822                         Class.forName(principal.getPrincipalClass(), false,
 823                                       ClassLoader.getSystemClassLoader());
 824                 principalSet = scs.getSubject().getPrincipals(pClass);
 825             } catch (Exception e) {
 826                 if (debug != null) {
 827                     debug.println("problem finding Principal Class " +
 828                                   "when expanding SELF permission: " +
 829                                   e.toString());
 830                 }
 831             }
 832 
 833             if (principalSet == null) {
 834                 // error
 835                 return new String[0][0];
 836             }
 837 
 838             String[][] info = new String[principalSet.size()][2];
 839 
 840             int i = 0;
 841             for (Principal p : principalSet) {
 842                 info[i][0] = p.getClass().getName();
 843                 info[i][1] = p.getName();
 844                 i++;
 845             }
 846             return info;
 847 
 848         } else {
 849 
 850             // build a PrivateCredentialPermission for every
 851             // one of the current Subject's principals
 852 
 853             // the accCs is guaranteed to be a SubjectCodeSource
 854             // because the earlier CodeSource.implies succeeded
 855             SubjectCodeSource scs = (SubjectCodeSource)accCs;
 856             Set<Principal> principalSet = scs.getSubject().getPrincipals();
 857 
 858             String[][] info = new String[principalSet.size()][2];
 859 
 860             int i = 0;
 861             for (Principal p : principalSet) {
 862                 info[i][0] = p.getClass().getName();
 863                 info[i][1] = p.getName();
 864                 i++;
 865             }
 866             return info;
 867         }
 868     }
 869 
 870     /*
 871      * Returns the signer certificates from the list of certificates associated
 872      * with the given code source.
 873      *
 874      * The signer certificates are those certificates that were used to verify
 875      * signed code originating from the codesource location.
 876      *
 877      * This method assumes that in the given code source, each signer
 878      * certificate is followed by its supporting certificate chain
 879      * (which may be empty), and that the signer certificate and its
 880      * supporting certificate chain are ordered bottom-to-top (i.e., with the
 881      * signer certificate first and the (root) certificate authority last).
 882      */
 883     Certificate[] getSignerCertificates(CodeSource cs) {
 884         Certificate[] certs = null;
 885         if ((certs = cs.getCertificates()) == null) {
 886             return null;
 887         }
 888         for (int i = 0; i < certs.length; i++) {
 889             if (!(certs[i] instanceof X509Certificate))
 890                 return cs.getCertificates();
 891         }
 892 
 893         // Do we have to do anything?
 894         int i = 0;
 895         int count = 0;
 896         while (i < certs.length) {
 897             count++;
 898             while (((i+1) < certs.length)
 899                    && ((X509Certificate)certs[i]).getIssuerDN().equals(
 900                            ((X509Certificate)certs[i+1]).getSubjectDN())) {
 901                 i++;
 902             }
 903             i++;
 904         }
 905         if (count == certs.length) {
 906             // Done
 907             return certs;
 908         }
 909 
 910         ArrayList<Certificate> userCertList = new ArrayList<>();
 911         i = 0;
 912         while (i < certs.length) {
 913             userCertList.add(certs[i]);
 914             while (((i+1) < certs.length)
 915                    && ((X509Certificate)certs[i]).getIssuerDN().equals(
 916                            ((X509Certificate)certs[i+1]).getSubjectDN())) {
 917                 i++;
 918             }
 919             i++;
 920         }
 921         Certificate[] userCerts = new Certificate[userCertList.size()];
 922         userCertList.toArray(userCerts);
 923         return userCerts;
 924     }
 925 
 926     private CodeSource canonicalizeCodebase(CodeSource cs,
 927                                             boolean extractSignerCerts) {
 928         CodeSource canonCs = cs;
 929         if (cs.getLocation() != null &&
 930             cs.getLocation().getProtocol().equalsIgnoreCase("file")) {
 931             try {
 932                 String path = cs.getLocation().getFile().replace
 933                                                         ('/',
 934                                                         File.separatorChar);
 935                 URL csUrl = null;
 936                 if (path.endsWith("*")) {
 937                     // remove trailing '*' because it causes canonicalization
 938                     // to fail on win32
 939                     path = path.substring(0, path.length()-1);
 940                     boolean appendFileSep = false;
 941                     if (path.endsWith(File.separator)) {
 942                         appendFileSep = true;
 943                     }
 944                     if (path.equals("")) {
 945                         path = System.getProperty("user.dir");
 946                     }
 947                     File f = new File(path);
 948                     path = f.getCanonicalPath();
 949                     StringBuilder sb = new StringBuilder(path);
 950                     // reappend '*' to canonicalized filename (note that
 951                     // canonicalization may have removed trailing file
 952                     // separator, so we have to check for that, too)
 953                     if (!path.endsWith(File.separator) &&
 954                         (appendFileSep || f.isDirectory())) {
 955                         sb.append(File.separatorChar);
 956                     }
 957                     sb.append('*');
 958                     path = sb.toString();
 959                 } else {
 960                     path = new File(path).getCanonicalPath();
 961                 }
 962                 csUrl = new File(path).toURL();
 963 
 964                 if (cs instanceof SubjectCodeSource) {
 965                     SubjectCodeSource scs = (SubjectCodeSource)cs;
 966                     if (extractSignerCerts) {
 967                         canonCs = new SubjectCodeSource(scs.getSubject(),
 968                                                         scs.getPrincipals(),
 969                                                         csUrl,
 970                                                         getSignerCertificates(scs));
 971                     } else {
 972                         canonCs = new SubjectCodeSource(scs.getSubject(),
 973                                                         scs.getPrincipals(),
 974                                                         csUrl,
 975                                                         scs.getCertificates());
 976                     }
 977                 } else {
 978                     if (extractSignerCerts) {
 979                         canonCs = new CodeSource(csUrl,
 980                                                  getSignerCertificates(cs));
 981                     } else {
 982                         canonCs = new CodeSource(csUrl,
 983                                                  cs.getCertificates());
 984                     }
 985                 }
 986             } catch (IOException ioe) {
 987                 // leave codesource as it is, unless we have to extract its
 988                 // signer certificates
 989                 if (extractSignerCerts) {
 990                     if (!(cs instanceof SubjectCodeSource)) {
 991                         canonCs = new CodeSource(cs.getLocation(),
 992                                                 getSignerCertificates(cs));
 993                     } else {
 994                         SubjectCodeSource scs = (SubjectCodeSource)cs;
 995                         canonCs = new SubjectCodeSource(scs.getSubject(),
 996                                                 scs.getPrincipals(),
 997                                                 scs.getLocation(),
 998                                                 getSignerCertificates(scs));
 999                     }
1000                 }
1001             }
1002         } else {
1003             if (extractSignerCerts) {
1004                 if (!(cs instanceof SubjectCodeSource)) {
1005                     canonCs = new CodeSource(cs.getLocation(),
1006                                         getSignerCertificates(cs));
1007                 } else {
1008                     SubjectCodeSource scs = (SubjectCodeSource)cs;
1009                     canonCs = new SubjectCodeSource(scs.getSubject(),
1010                                         scs.getPrincipals(),
1011                                         scs.getLocation(),
1012                                         getSignerCertificates(scs));
1013                 }
1014             }
1015         }
1016         return canonCs;
1017     }
1018 
1019     /**
1020      * Each entry in the policy configuration file is represented by a
1021      * PolicyEntry object.  <p>
1022      *
1023      * A PolicyEntry is a (CodeSource,Permission) pair.  The
1024      * CodeSource contains the (URL, PublicKey) that together identify
1025      * where the Java bytecodes come from and who (if anyone) signed
1026      * them.  The URL could refer to localhost.  The URL could also be
1027      * null, meaning that this policy entry is given to all comers, as
1028      * long as they match the signer field.  The signer could be null,
1029      * meaning the code is not signed. <p>
1030      *
1031      * The Permission contains the (Type, Name, Action) triplet. <p>
1032      *
1033      * For now, the Policy object retrieves the public key from the
1034      * X.509 certificate on disk that corresponds to the signedBy
1035      * alias specified in the Policy config file.  For reasons of
1036      * efficiency, the Policy object keeps a hashtable of certs already
1037      * read in.  This could be replaced by a secure internal key
1038      * store.
1039      *
1040      * <p>
1041      * For example, the entry
1042      * <pre>
1043      *          permission java.io.File "/tmp", "read,write",
1044      *          signedBy "Duke";
1045      * </pre>
1046      * is represented internally
1047      * <pre>
1048      *
1049      * FilePermission f = new FilePermission("/tmp", "read,write");
1050      * PublicKey p = publickeys.get("Duke");
1051      * URL u = InetAddress.getLocalHost();
1052      * CodeBase c = new CodeBase( p, u );
1053      * pe = new PolicyEntry(f, c);
1054      * </pre>
1055      *
1056      * @author Marianne Mueller
1057      * @author Roland Schemers
1058      * @see java.security.CodeSource
1059      * @see java.security.Policy
1060      * @see java.security.Permissions
1061      * @see java.security.ProtectionDomain
1062      */
1063     private static class PolicyEntry {
1064 
1065         CodeSource codesource;
1066         Vector<Permission> permissions;
1067 
1068         /**
1069          * Given a Permission and a CodeSource, create a policy entry.
1070          *
1071          * XXX Decide if/how to add validity fields and "purpose" fields to
1072          * XXX policy entries
1073          *
1074          * @param cs the CodeSource, which encapsulates the URL and the public
1075          *        key attributes from the policy config file. Validity checks
1076          *        are performed on the public key before PolicyEntry is called.
1077          *
1078          */
1079         PolicyEntry(CodeSource cs) {
1080             this.codesource = cs;
1081             this.permissions = new Vector<Permission>();
1082         }
1083 
1084         /**
1085          * add a Permission object to this entry.
1086          */
1087         void add(Permission p) {
1088             permissions.addElement(p);
1089         }
1090 
1091         /**
1092          * Return the CodeSource for this policy entry
1093          */
1094         CodeSource getCodeSource() {
1095             return this.codesource;
1096         }
1097 
1098         @Override
1099         public String toString(){
1100             StringBuilder sb = new StringBuilder();
1101             sb.append(rb.getString("LPARAM"));
1102             sb.append(getCodeSource());
1103             sb.append("\n");
1104             for (int j = 0; j < permissions.size(); j++) {
1105                 Permission p = permissions.elementAt(j);
1106                 sb.append(rb.getString("SPACE"));
1107                 sb.append(rb.getString("SPACE"));
1108                 sb.append(p);
1109                 sb.append(rb.getString("NEWLINE"));
1110             }
1111             sb.append(rb.getString("RPARAM"));
1112             sb.append(rb.getString("NEWLINE"));
1113             return sb.toString();
1114         }
1115 
1116     }
1117 }
1118 
1119 @SuppressWarnings("deprecation")
1120 class PolicyPermissions extends PermissionCollection {
1121 
1122     private static final long serialVersionUID = -1954188373270545523L;
1123 
1124     private CodeSource codesource;
1125     private Permissions perms;
1126     private AuthPolicyFile policy;
1127     private boolean notInit; // have we pulled in the policy permissions yet?
1128     private Vector<Permission> additionalPerms;
1129 
1130     PolicyPermissions(AuthPolicyFile policy,
1131                       CodeSource codesource)
1132     {
1133         this.codesource = codesource;
1134         this.policy = policy;
1135         this.perms = null;
1136         this.notInit = true;
1137         this.additionalPerms = null;
1138     }
1139 
1140     @Override
1141     public void add(Permission permission) {
1142         if (isReadOnly())
1143             throw new SecurityException
1144             (AuthPolicyFile.rb.getString
1145             ("attempt.to.add.a.Permission.to.a.readonly.PermissionCollection"));
1146 
1147         if (perms == null) {
1148             if (additionalPerms == null) {
1149                 additionalPerms = new Vector<Permission>();
1150             }
1151             additionalPerms.add(permission);
1152         } else {
1153             perms.add(permission);
1154         }
1155     }
1156 
1157     private synchronized void init() {
1158         if (notInit) {
1159             if (perms == null) {
1160                 perms = new Permissions();
1161             }
1162             if (additionalPerms != null) {
1163                 Enumeration<Permission> e = additionalPerms.elements();
1164                 while (e.hasMoreElements()) {
1165                     perms.add(e.nextElement());
1166                 }
1167                 additionalPerms = null;
1168             }
1169             policy.getPermissions(perms, codesource);
1170             notInit = false;
1171         }
1172     }
1173 
1174     @Override
1175     public boolean implies(Permission permission) {
1176         if (notInit) {
1177             init();
1178         }
1179         return perms.implies(permission);
1180     }
1181 
1182     @Override
1183     public Enumeration<Permission> elements() {
1184         if (notInit) {
1185             init();
1186         }
1187         return perms.elements();
1188     }
1189 
1190     @Override
1191     public String toString() {
1192         if (notInit) {
1193             init();
1194         }
1195         return perms.toString();
1196     }
1197 }