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