Path: blob/master/src/java.base/share/classes/sun/security/provider/PolicyFile.java
67848 views
/*1* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.security.provider;2627import java.io.*;28import java.lang.reflect.*;29import java.net.MalformedURLException;30import java.net.URL;31import java.net.URI;32import java.nio.file.Files;33import java.nio.file.Path;34import java.util.*;35import java.security.*;36import java.security.cert.Certificate;37import java.security.cert.X509Certificate;38import javax.security.auth.Subject;39import javax.security.auth.x500.X500Principal;40import java.net.SocketPermission;41import java.net.NetPermission;42import java.util.concurrent.ConcurrentHashMap;43import jdk.internal.access.JavaSecurityAccess;44import jdk.internal.access.SharedSecrets;45import jdk.internal.util.StaticProperty;46import sun.nio.fs.DefaultFileSystemProvider;47import sun.security.util.*;48import sun.net.www.ParseUtil;4950import static java.nio.charset.StandardCharsets.UTF_8;51import static jdk.internal.access.JavaSecurityAccess.ProtectionDomainCache;5253/**54* This class represents a default Policy implementation for the55* "JavaPolicy" type.56*57* <p> This object stores the policy for the entire Java runtime,58* and is the amalgamation of multiple static policy59* configurations that resides in files.60* The algorithm for locating the policy file(s) and reading their61* information into this <code>Policy</code> object is:62*63* <ol>64* <li>65* Read in and load the default policy file named66* <JAVA_HOME>/lib/security/default.policy. <JAVA_HOME> refers67* to the value of the java.home system property, and specifies the directory68* where the JRE is installed. This policy file grants permissions to the69* modules loaded by the platform class loader. If the default policy file70* cannot be loaded, a fatal InternalError is thrown as these permissions71* are needed in order for the runtime to operate correctly.72* <li>73* Loop through the <code>java.security.Security</code> properties,74* and <i>policy.url.1</i>, <i>policy.url.2</i>, ...,75* <i>policy.url.X</i>". These properties are set76* in the Java security properties file, which is located in the file named77* <JAVA_HOME>/conf/security/java.security.78* Each property value specifies a <code>URL</code> pointing to a79* policy file to be loaded. Read in and load each policy.80*81* If none of these could be loaded, use a builtin static policy82* equivalent to the conf/security/java.policy file.83*84* <li>85* The <code>java.lang.System</code> property <i>java.security.policy</i>86* may also be set to a <code>URL</code> pointing to another policy file87* (which is the case when a user uses the -D switch at runtime).88* If this property is defined, and its use is allowed by the89* security property file (the Security property,90* <i>policy.allowSystemProperty</i> is set to <i>true</i>),91* also load that policy.92*93* If the <i>java.security.policy</i> property is defined using94* "==" (rather than "="), then load the specified policy file and ignore95* all other configured policies. Note, that the default.policy file is96* also loaded, as specified in the first step of the algorithm above.97* If the specified policy file cannot be loaded, use a builtin static policy98* equivalent to the default conf/security/java.policy file.99* </ol>100*101* Each policy file consists of one or more grant entries, each of102* which consists of a number of permission entries.103*104* <pre>105* grant signedBy "<b>alias</b>", codeBase "<b>URL</b>",106* principal <b>principalClass</b> "<b>principalName</b>",107* principal <b>principalClass</b> "<b>principalName</b>",108* ... {109*110* permission <b>Type</b> "<b>name</b> "<b>action</b>",111* signedBy "<b>alias</b>";112* permission <b>Type</b> "<b>name</b> "<b>action</b>",113* signedBy "<b>alias</b>";114* ....115* };116* </pre>117*118* All non-bold items above must appear as is (although case119* doesn't matter and some are optional, as noted below).120* principal entries are optional and need not be present.121* Italicized items represent variable values.122*123* <p> A grant entry must begin with the word <code>grant</code>.124* The <code>signedBy</code>,<code>codeBase</code> and <code>principal</code>125* name/value pairs are optional.126* If they are not present, then any signer (including unsigned code)127* will match, and any codeBase will match.128* Note that the <i>principalClass</i>129* may be set to the wildcard value, *, which allows it to match130* any <code>Principal</code> class. In addition, the <i>principalName</i>131* may also be set to the wildcard value, *, allowing it to match132* any <code>Principal</code> name. When setting the <i>principalName</i>133* to the *, do not surround the * with quotes.134*135* <p> A permission entry must begin with the word <code>permission</code>.136* The word <code><i>Type</i></code> in the template above is137* a specific permission type, such as <code>java.io.FilePermission</code>138* or <code>java.lang.RuntimePermission</code>.139*140* <p> The "<i>action</i>" is required for141* many permission types, such as <code>java.io.FilePermission</code>142* (where it specifies what type of file access that is permitted).143* It is not required for categories such as144* <code>java.lang.RuntimePermission</code>145* where it is not necessary - you either have the146* permission specified by the <code>"<i>name</i>"</code>147* value following the type name or you don't.148*149* <p> The <code>signedBy</code> name/value pair for a permission entry150* is optional. If present, it indicates a signed permission. That is,151* the permission class itself must be signed by the given alias in152* order for it to be granted. For example,153* suppose you have the following grant entry:154*155* <pre>156* grant principal foo.com.Principal "Duke" {157* permission Foo "foobar", signedBy "FooSoft";158* }159* </pre>160*161* <p> Then this permission of type <i>Foo</i> is granted if the162* <code>Foo.class</code> permission has been signed by the163* "FooSoft" alias, or if XXX <code>Foo.class</code> is a164* system class (i.e., is found on the CLASSPATH).165*166* <p> Items that appear in an entry must appear in the specified order167* (<code>permission</code>, <i>Type</i>, "<i>name</i>", and168* "<i>action</i>"). An entry is terminated with a semicolon.169*170* <p> Case is unimportant for the identifiers (<code>permission</code>,171* <code>signedBy</code>, <code>codeBase</code>, etc.) but is172* significant for the <i>Type</i>173* or for any string that is passed in as a value.174*175* <p> An example of two entries in a policy configuration file is176* <pre>177* // if the code is comes from "foo.com" and is running as "Duke",178* // grant it read/write to all files in /tmp.179*180* grant codeBase "foo.com", principal foo.com.Principal "Duke" {181* permission java.io.FilePermission "/tmp/*", "read,write";182* };183*184* // grant any code running as "Duke" permission to read185* // the "java.vendor" Property.186*187* grant principal foo.com.Principal "Duke" {188* permission java.util.PropertyPermission "java.vendor";189*190*191* </pre>192* This Policy implementation supports special handling of any193* permission that contains the string, "<b>${{self}}</b>", as part of194* its target name. When such a permission is evaluated195* (such as during a security check), <b>${{self}}</b> is replaced196* with one or more Principal class/name pairs. The exact197* replacement performed depends upon the contents of the198* grant clause to which the permission belongs.199* <p>200*201* If the grant clause does not contain any principal information,202* the permission will be ignored (permissions containing203* <b>${{self}}</b> in their target names are only valid in the context204* of a principal-based grant clause). For example, BarPermission205* will always be ignored in the following grant clause:206*207* <pre>208* grant codebase "www.foo.com", signedby "duke" {209* permission BarPermission "... ${{self}} ...";210* };211* </pre>212*213* If the grant clause contains principal information, <b>${{self}}</b>214* will be replaced with that same principal information.215* For example, <b>${{self}}</b> in BarPermission will be replaced by216* <b>javax.security.auth.x500.X500Principal "cn=Duke"</b>217* in the following grant clause:218*219* <pre>220* grant principal javax.security.auth.x500.X500Principal "cn=Duke" {221* permission BarPermission "... ${{self}} ...";222* };223* </pre>224*225* If there is a comma-separated list of principals in the grant226* clause, then <b>${{self}}</b> will be replaced by the same227* comma-separated list or principals.228* In the case where both the principal class and name are229* wildcarded in the grant clause, <b>${{self}}</b> is replaced230* with all the principals associated with the <code>Subject</code>231* in the current <code>AccessControlContext</code>.232*233* <p> For PrivateCredentialPermissions, you can also use "<b>self</b>"234* instead of "<b>${{self}}</b>". However the use of "<b>self</b>" is235* deprecated in favour of "<b>${{self}}</b>".236*237* @see java.security.CodeSource238* @see java.security.Permissions239* @see java.security.ProtectionDomain240*/241@SuppressWarnings("removal")242public class PolicyFile extends java.security.Policy {243244private static final Debug debug = Debug.getInstance("policy");245246private static final String SELF = "${{self}}";247private static final String X500PRINCIPAL =248"javax.security.auth.x500.X500Principal";249private static final String POLICY = "java.security.policy";250private static final String POLICY_URL = "policy.url.";251252private static final int DEFAULT_CACHE_SIZE = 1;253254// contains the policy grant entries, PD cache, and alias mapping255// can be updated if refresh() is called256private volatile PolicyInfo policyInfo;257258private boolean expandProperties = true;259private boolean allowSystemProperties = true;260private boolean notUtf8 = false;261private URL url;262263// for use with the reflection API264private static final Class<?>[] PARAMS0 = { };265private static final Class<?>[] PARAMS1 = { String.class };266private static final Class<?>[] PARAMS2 = { String.class, String.class };267268/**269* When a policy file has a syntax error, the exception code may generate270* another permission check and this can cause the policy file to be parsed271* repeatedly, leading to a StackOverflowError or ClassCircularityError.272* To avoid this, this set is populated with policy files that have been273* previously parsed and have syntax errors, so that they can be274* subsequently ignored.275*/276private static Set<URL> badPolicyURLs =277Collections.newSetFromMap(new ConcurrentHashMap<URL,Boolean>());278279/**280* Use the platform's default file system to avoid recursive initialization281* issues when the VM is configured to use a custom file system provider.282*/283private static final java.nio.file.FileSystem builtInFS =284DefaultFileSystemProvider.theFileSystem();285286/**287* Initializes the Policy object and reads the default policy288* configuration file(s) into the Policy object.289*/290public PolicyFile() {291init((URL)null);292}293294/**295* Initializes the Policy object and reads the default policy296* from the specified URL only.297*/298public PolicyFile(URL url) {299this.url = url;300init(url);301}302303/**304* Initializes the Policy object and reads the default policy305* configuration file(s) into the Policy object.306*307* See the class description for details on the algorithm used to308* initialize the Policy object.309*/310private void init(URL url) {311// Properties are set once for each init(); ignore changes312// between diff invocations of initPolicyFile(policy, url, info).313String numCacheStr =314AccessController.doPrivileged(new PrivilegedAction<>() {315@Override316public String run() {317expandProperties = "true".equalsIgnoreCase318(Security.getProperty("policy.expandProperties"));319allowSystemProperties = "true".equalsIgnoreCase320(Security.getProperty("policy.allowSystemProperty"));321notUtf8 = "false".equalsIgnoreCase322(System.getProperty("sun.security.policy.utf8"));323return System.getProperty("sun.security.policy.numcaches");324}});325326int numCaches;327if (numCacheStr != null) {328try {329numCaches = Integer.parseInt(numCacheStr);330} catch (NumberFormatException e) {331numCaches = DEFAULT_CACHE_SIZE;332}333} else {334numCaches = DEFAULT_CACHE_SIZE;335}336PolicyInfo newInfo = new PolicyInfo(numCaches);337initPolicyFile(newInfo, url);338policyInfo = newInfo;339}340341private void initPolicyFile(final PolicyInfo newInfo, final URL url) {342343// always load default.policy344AccessController.doPrivileged(new PrivilegedAction<>() {345@Override346public Void run() {347initDefaultPolicy(newInfo);348return null;349}350});351352if (url != null) {353354/**355* If the caller specified a URL via Policy.getInstance,356* we only read from default.policy and that URL.357*/358359if (debug != null) {360debug.println("reading " + url);361}362AccessController.doPrivileged(new PrivilegedAction<>() {363@Override364public Void run() {365if (init(url, newInfo) == false) {366// use static policy if all else fails367initStaticPolicy(newInfo);368}369return null;370}371});372373} else {374375/**376* Caller did not specify URL via Policy.getInstance.377* Read from URLs listed in the java.security properties file.378*/379380boolean loaded_one = initPolicyFile(POLICY, POLICY_URL, newInfo);381// To maintain strict backward compatibility382// we load the static policy only if POLICY load failed383if (!loaded_one) {384// use static policy if all else fails385initStaticPolicy(newInfo);386}387}388}389390private boolean initPolicyFile(final String propname, final String urlname,391final PolicyInfo newInfo) {392boolean loadedPolicy =393AccessController.doPrivileged(new PrivilegedAction<>() {394@Override395public Boolean run() {396boolean loaded_policy = false;397398if (allowSystemProperties) {399String extra_policy = System.getProperty(propname);400if (extra_policy != null) {401boolean overrideAll = false;402if (extra_policy.startsWith("=")) {403overrideAll = true;404extra_policy = extra_policy.substring(1);405}406try {407extra_policy =408PropertyExpander.expand(extra_policy);409URL policyURL;410411File policyFile = new File(extra_policy);412if (policyFile.exists()) {413policyURL = ParseUtil.fileToEncodedURL414(new File(policyFile.getCanonicalPath()));415} else {416policyURL = new URL(extra_policy);417}418if (debug != null) {419debug.println("reading "+policyURL);420}421if (init(policyURL, newInfo)) {422loaded_policy = true;423}424} catch (Exception e) {425// ignore.426if (debug != null) {427debug.println("caught exception: "+e);428}429}430if (overrideAll) {431if (debug != null) {432debug.println("overriding other policies!");433}434return Boolean.valueOf(loaded_policy);435}436}437}438439int n = 1;440String policy_uri;441442while ((policy_uri = Security.getProperty(urlname+n)) != null) {443try {444URL policy_url = null;445String expanded_uri = PropertyExpander.expand446(policy_uri).replace(File.separatorChar, '/');447448if (policy_uri.startsWith("file:${java.home}/") ||449policy_uri.startsWith("file:${user.home}/")) {450451// this special case accommodates452// the situation java.home/user.home453// expand to a single slash, resulting in454// a file://foo URI455policy_url = new File456(expanded_uri.substring(5)).toURI().toURL();457} else {458policy_url = new URI(expanded_uri).toURL();459}460461if (debug != null) {462debug.println("reading " + policy_url);463}464if (init(policy_url, newInfo)) {465loaded_policy = true;466}467} catch (Exception e) {468if (debug != null) {469debug.println(470"Debug info only. Error reading policy " +e);471e.printStackTrace();472}473// ignore that policy474}475n++;476}477return Boolean.valueOf(loaded_policy);478}479});480481return loadedPolicy;482}483484private void initDefaultPolicy(PolicyInfo newInfo) {485Path defaultPolicy = builtInFS.getPath(StaticProperty.javaHome(),486"lib",487"security",488"default.policy");489if (debug != null) {490debug.println("reading " + defaultPolicy);491}492try (BufferedReader br = Files.newBufferedReader(defaultPolicy)) {493494PolicyParser pp = new PolicyParser(expandProperties);495pp.read(br);496497Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();498while (enum_.hasMoreElements()) {499PolicyParser.GrantEntry ge = enum_.nextElement();500addGrantEntry(ge, null, newInfo);501}502} catch (Exception e) {503throw new InternalError("Failed to load default.policy", e);504}505}506507/**508* Reads a policy configuration into the Policy object using a509* Reader object.510*/511private boolean init(URL policy, PolicyInfo newInfo) {512513// skip parsing policy file if it has been previously parsed and514// has syntax errors515if (badPolicyURLs.contains(policy)) {516if (debug != null) {517debug.println("skipping bad policy file: " + policy);518}519return false;520}521522try (InputStreamReader isr =523getInputStreamReader(PolicyUtil.getInputStream(policy))) {524525PolicyParser pp = new PolicyParser(expandProperties);526pp.read(isr);527528KeyStore keyStore = null;529try {530keyStore = PolicyUtil.getKeyStore531(policy,532pp.getKeyStoreUrl(),533pp.getKeyStoreType(),534pp.getKeyStoreProvider(),535pp.getStorePassURL(),536debug);537} catch (Exception e) {538// ignore, treat it like we have no keystore539if (debug != null) {540debug.println("Debug info only. Ignoring exception.");541e.printStackTrace();542}543}544545Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();546while (enum_.hasMoreElements()) {547PolicyParser.GrantEntry ge = enum_.nextElement();548addGrantEntry(ge, keyStore, newInfo);549}550return true;551} catch (PolicyParser.ParsingException pe) {552// record bad policy file to avoid later reparsing it553badPolicyURLs.add(policy);554Object[] source = {policy, pe.getNonlocalizedMessage()};555System.err.println(LocalizedMessage.getNonlocalized556(POLICY + ".error.parsing.policy.message", source));557if (debug != null) {558pe.printStackTrace();559}560} catch (Exception e) {561if (debug != null) {562debug.println("error parsing "+policy);563debug.println(e.toString());564e.printStackTrace();565}566}567568return false;569}570571private InputStreamReader getInputStreamReader(InputStream is) {572/*573* Read in policy using UTF-8 by default.574*575* Check non-standard system property to see if the default encoding576* should be used instead.577*/578return (notUtf8)579? new InputStreamReader(is)580: new InputStreamReader(is, UTF_8);581}582583private void initStaticPolicy(final PolicyInfo newInfo) {584if (debug != null) {585debug.println("Initializing with static permissions");586}587AccessController.doPrivileged(new PrivilegedAction<>() {588@Override589public Void run() {590PolicyEntry pe = new PolicyEntry(new CodeSource(null,591(Certificate[]) null));592pe.add(SecurityConstants.LOCAL_LISTEN_PERMISSION);593pe.add(new PropertyPermission("java.version",594SecurityConstants.PROPERTY_READ_ACTION));595pe.add(new PropertyPermission("java.vendor",596SecurityConstants.PROPERTY_READ_ACTION));597pe.add(new PropertyPermission("java.vendor.url",598SecurityConstants.PROPERTY_READ_ACTION));599pe.add(new PropertyPermission("java.class.version",600SecurityConstants.PROPERTY_READ_ACTION));601pe.add(new PropertyPermission("os.name",602SecurityConstants.PROPERTY_READ_ACTION));603pe.add(new PropertyPermission("os.version",604SecurityConstants.PROPERTY_READ_ACTION));605pe.add(new PropertyPermission("os.arch",606SecurityConstants.PROPERTY_READ_ACTION));607pe.add(new PropertyPermission("file.separator",608SecurityConstants.PROPERTY_READ_ACTION));609pe.add(new PropertyPermission("path.separator",610SecurityConstants.PROPERTY_READ_ACTION));611pe.add(new PropertyPermission("line.separator",612SecurityConstants.PROPERTY_READ_ACTION));613pe.add(new PropertyPermission614("java.specification.version",615SecurityConstants.PROPERTY_READ_ACTION));616pe.add(new PropertyPermission617("java.specification.vendor",618SecurityConstants.PROPERTY_READ_ACTION));619pe.add(new PropertyPermission620("java.specification.name",621SecurityConstants.PROPERTY_READ_ACTION));622pe.add(new PropertyPermission623("java.vm.specification.version",624SecurityConstants.PROPERTY_READ_ACTION));625pe.add(new PropertyPermission626("java.vm.specification.vendor",627SecurityConstants.PROPERTY_READ_ACTION));628pe.add(new PropertyPermission629("java.vm.specification.name",630SecurityConstants.PROPERTY_READ_ACTION));631pe.add(new PropertyPermission("java.vm.version",632SecurityConstants.PROPERTY_READ_ACTION));633pe.add(new PropertyPermission("java.vm.vendor",634SecurityConstants.PROPERTY_READ_ACTION));635pe.add(new PropertyPermission("java.vm.name",636SecurityConstants.PROPERTY_READ_ACTION));637638// No need to sync because noone has access to newInfo yet639newInfo.policyEntries.add(pe);640641return null;642}643});644}645646/**647* Given a GrantEntry, create a codeSource.648*649* @return null if signedBy alias is not recognized650*/651private CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore,652PolicyInfo newInfo) throws java.net.MalformedURLException653{654Certificate[] certs = null;655if (ge.signedBy != null) {656certs = getCertificates(keyStore, ge.signedBy, newInfo);657if (certs == null) {658// we don't have a key for this alias,659// just return660if (debug != null) {661debug.println(" -- No certs for alias '" +662ge.signedBy + "' - ignoring entry");663}664return null;665}666}667668URL location;669670if (ge.codeBase != null)671location = new URL(ge.codeBase);672else673location = null;674675return (canonicalizeCodebase(new CodeSource(location, certs),false));676}677678/**679* Add one policy entry to the list.680*/681private void addGrantEntry(PolicyParser.GrantEntry ge,682KeyStore keyStore, PolicyInfo newInfo) {683684if (debug != null) {685debug.println("Adding policy entry: ");686debug.println(" signedBy " + ge.signedBy);687debug.println(" codeBase " + ge.codeBase);688if (ge.principals != null) {689for (PolicyParser.PrincipalEntry pppe : ge.principals) {690debug.println(" " + pppe.toString());691}692}693}694695try {696CodeSource codesource = getCodeSource(ge, keyStore, newInfo);697// skip if signedBy alias was unknown...698if (codesource == null) return;699700// perform keystore alias principal replacement.701// for example, if alias resolves to X509 certificate,702// replace principal with: <X500Principal class> <SubjectDN>703// -- skip if alias is unknown704if (replacePrincipals(ge.principals, keyStore) == false)705return;706PolicyEntry entry = new PolicyEntry(codesource, ge.principals);707Enumeration<PolicyParser.PermissionEntry> enum_ =708ge.permissionElements();709while (enum_.hasMoreElements()) {710PolicyParser.PermissionEntry pe = enum_.nextElement();711712try {713// perform ${{ ... }} expansions within permission name714expandPermissionName(pe, keyStore);715716// XXX special case PrivateCredentialPermission-SELF717Permission perm;718if (pe.permission.equals719("javax.security.auth.PrivateCredentialPermission") &&720pe.name.endsWith(" self")) {721pe.name = pe.name.substring(0, pe.name.indexOf("self"))722+ SELF;723}724// check for self725if (pe.name != null && pe.name.indexOf(SELF) != -1) {726// Create a "SelfPermission" , it could be an727// an unresolved permission which will be resolved728// when implies is called729// Add it to entry730Certificate[] certs;731if (pe.signedBy != null) {732certs = getCertificates(keyStore,733pe.signedBy,734newInfo);735} else {736certs = null;737}738perm = new SelfPermission(pe.permission,739pe.name,740pe.action,741certs);742} else {743perm = getInstance(pe.permission,744pe.name,745pe.action);746}747entry.add(perm);748if (debug != null) {749debug.println(" "+perm);750}751} catch (ClassNotFoundException cnfe) {752Certificate[] certs;753if (pe.signedBy != null) {754certs = getCertificates(keyStore,755pe.signedBy,756newInfo);757} else {758certs = null;759}760761// only add if we had no signer or we had762// a signer and found the keys for it.763if (certs != null || pe.signedBy == null) {764Permission perm = new UnresolvedPermission(765pe.permission,766pe.name,767pe.action,768certs);769entry.add(perm);770if (debug != null) {771debug.println(" "+perm);772}773}774} catch (java.lang.reflect.InvocationTargetException ite) {775Object[] source = {pe.permission,776ite.getCause().toString()};777System.err.println(778LocalizedMessage.getNonlocalized(779POLICY + ".error.adding.Permission.perm.message",780source));781} catch (Exception e) {782Object[] source = {pe.permission,783e.toString()};784System.err.println(785LocalizedMessage.getNonlocalized(786POLICY + ".error.adding.Permission.perm.message",787source));788}789}790791// No need to sync because noone has access to newInfo yet792newInfo.policyEntries.add(entry);793} catch (Exception e) {794Object[] source = {e.toString()};795System.err.println(796LocalizedMessage.getNonlocalized(797POLICY + ".error.adding.Entry.message",798source));799}800if (debug != null)801debug.println();802}803804/**805* Returns a new Permission object of the given Type. The Permission is806* created by getting the807* Class object using the <code>Class.forName</code> method, and using808* the reflection API to invoke the (String name, String actions)809* constructor on the810* object.811*812* @param type the type of Permission being created.813* @param name the name of the Permission being created.814* @param actions the actions of the Permission being created.815*816* @exception ClassNotFoundException if the particular Permission817* class could not be found.818*819* @exception IllegalAccessException if the class or initializer is820* not accessible.821*822* @exception InstantiationException if getInstance tries to823* instantiate an abstract class or an interface, or if the824* instantiation fails for some other reason.825*826* @exception NoSuchMethodException if the (String, String) constructor827* is not found.828*829* @exception InvocationTargetException if the underlying Permission830* constructor throws an exception.831*832*/833834private static final Permission getInstance(String type,835String name,836String actions)837throws ClassNotFoundException,838InstantiationException,839IllegalAccessException,840NoSuchMethodException,841InvocationTargetException842{843Class<?> pc = Class.forName(type, false, null);844Permission answer = getKnownPermission(pc, name, actions);845if (answer != null) {846return answer;847}848if (!Permission.class.isAssignableFrom(pc)) {849// not the right subtype850throw new ClassCastException(type + " is not a Permission");851}852853if (name == null && actions == null) {854try {855Constructor<?> c = pc.getConstructor(PARAMS0);856return (Permission) c.newInstance(new Object[] {});857} catch (NoSuchMethodException ne) {858try {859Constructor<?> c = pc.getConstructor(PARAMS1);860return (Permission) c.newInstance(861new Object[] { name});862} catch (NoSuchMethodException ne1 ) {863Constructor<?> c = pc.getConstructor(PARAMS2);864return (Permission) c.newInstance(865new Object[] { name, actions });866}867}868} else {869if (name != null && actions == null) {870try {871Constructor<?> c = pc.getConstructor(PARAMS1);872return (Permission) c.newInstance(new Object[] { name});873} catch (NoSuchMethodException ne) {874Constructor<?> c = pc.getConstructor(PARAMS2);875return (Permission) c.newInstance(876new Object[] { name, actions });877}878} else {879Constructor<?> c = pc.getConstructor(PARAMS2);880return (Permission) c.newInstance(881new Object[] { name, actions });882}883}884}885886/**887* Creates one of the well-known permissions in the java.base module888* directly instead of via reflection. Keep list short to not penalize889* permissions from other modules.890*/891private static Permission getKnownPermission(Class<?> claz, String name,892String actions) {893if (claz.equals(FilePermission.class)) {894return new FilePermission(name, actions);895} else if (claz.equals(SocketPermission.class)) {896return new SocketPermission(name, actions);897} else if (claz.equals(RuntimePermission.class)) {898return new RuntimePermission(name, actions);899} else if (claz.equals(PropertyPermission.class)) {900return new PropertyPermission(name, actions);901} else if (claz.equals(NetPermission.class)) {902return new NetPermission(name, actions);903} else if (claz.equals(AllPermission.class)) {904return SecurityConstants.ALL_PERMISSION;905} else if (claz.equals(SecurityPermission.class)) {906return new SecurityPermission(name, actions);907} else {908return null;909}910}911912/**913* Creates one of the well-known principals in the java.base module914* directly instead of via reflection. Keep list short to not penalize915* principals from other modules.916*/917private static Principal getKnownPrincipal(Class<?> claz, String name) {918if (claz.equals(X500Principal.class)) {919return new X500Principal(name);920} else {921return null;922}923}924925/**926* Fetch all certs associated with this alias.927*/928private Certificate[] getCertificates929(KeyStore keyStore, String aliases, PolicyInfo newInfo) {930931List<Certificate> vcerts = null;932933StringTokenizer st = new StringTokenizer(aliases, ",");934int n = 0;935936while (st.hasMoreTokens()) {937String alias = st.nextToken().trim();938n++;939Certificate cert = null;940// See if this alias's cert has already been cached941synchronized (newInfo.aliasMapping) {942cert = (Certificate)newInfo.aliasMapping.get(alias);943944if (cert == null && keyStore != null) {945946try {947cert = keyStore.getCertificate(alias);948} catch (KeyStoreException kse) {949// never happens, because keystore has already been loaded950// when we call this951}952if (cert != null) {953newInfo.aliasMapping.put(alias, cert);954newInfo.aliasMapping.put(cert, alias);955}956}957}958959if (cert != null) {960if (vcerts == null)961vcerts = new ArrayList<>();962vcerts.add(cert);963}964}965966// make sure n == vcerts.size, since we are doing a logical *and*967if (vcerts != null && n == vcerts.size()) {968Certificate[] certs = new Certificate[vcerts.size()];969vcerts.toArray(certs);970return certs;971} else {972return null;973}974}975976/**977* Refreshes the policy object by re-reading all the policy files.978*/979@Override public void refresh() {980init(url);981}982983/**984* Evaluates the global policy for the permissions granted to985* the ProtectionDomain and tests whether the permission is986* granted.987*988* @param pd the ProtectionDomain to test989* @param p the Permission object to be tested for implication.990*991* @return true if "permission" is a proper subset of a permission992* granted to this ProtectionDomain.993*994* @see java.security.ProtectionDomain995*/996@Override997public boolean implies(ProtectionDomain pd, Permission p) {998ProtectionDomainCache pdMap = policyInfo.getPdMapping();999PermissionCollection pc = pdMap.get(pd);10001001if (pc != null) {1002return pc.implies(p);1003}10041005pc = getPermissions(pd);1006if (pc == null) {1007return false;1008}10091010// cache mapping of protection domain to its PermissionCollection1011pdMap.put(pd, pc);1012return pc.implies(p);1013}10141015/**1016* Examines this <code>Policy</code> and returns the permissions granted1017* to the specified <code>ProtectionDomain</code>. This includes1018* the permissions currently associated with the domain as well1019* as the policy permissions granted to the domain's1020* CodeSource, ClassLoader, and Principals.1021*1022* <p> Note that this <code>Policy</code> implementation has1023* special handling for PrivateCredentialPermissions.1024* When this method encounters a <code>PrivateCredentialPermission</code>1025* which specifies "self" as the <code>Principal</code> class and name,1026* it does not add that <code>Permission</code> to the returned1027* <code>PermissionCollection</code>. Instead, it builds1028* a new <code>PrivateCredentialPermission</code>1029* for each <code>Principal</code> associated with the provided1030* <code>Subject</code>. Each new <code>PrivateCredentialPermission</code>1031* contains the same Credential class as specified in the1032* originally granted permission, as well as the Class and name1033* for the respective <code>Principal</code>.1034*1035* @param domain the Permissions granted to this1036* <code>ProtectionDomain</code> are returned.1037*1038* @return the Permissions granted to the provided1039* <code>ProtectionDomain</code>.1040*/1041@Override1042public PermissionCollection getPermissions(ProtectionDomain domain) {1043Permissions perms = new Permissions();10441045if (domain == null)1046return perms;10471048// first get policy perms1049getPermissions(perms, domain);10501051// add static perms1052// - adding static perms after policy perms is necessary1053// to avoid a regression for 43010641054PermissionCollection pc = domain.getPermissions();1055if (pc != null) {1056synchronized (pc) {1057Enumeration<Permission> e = pc.elements();1058while (e.hasMoreElements()) {1059perms.add(FilePermCompat.newPermPlusAltPath(e.nextElement()));1060}1061}1062}10631064return perms;1065}10661067/**1068* Examines this Policy and creates a PermissionCollection object with1069* the set of permissions for the specified CodeSource.1070*1071* @param codesource the CodeSource associated with the caller.1072* This encapsulates the original location of the code (where the code1073* came from) and the public key(s) of its signer.1074*1075* @return the set of permissions according to the policy.1076*/1077@Override1078public PermissionCollection getPermissions(CodeSource codesource) {1079return getPermissions(new Permissions(), codesource);1080}10811082/**1083* Examines the global policy and returns the provided Permissions1084* object with additional permissions granted to the specified1085* ProtectionDomain.1086*1087* @param perms the Permissions to populate1088* @param pd the ProtectionDomain associated with the caller.1089*1090* @return the set of Permissions according to the policy.1091*/1092private PermissionCollection getPermissions(Permissions perms,1093ProtectionDomain pd ) {1094if (debug != null) {1095debug.println("getPermissions:\n\t" + printPD(pd));1096}10971098final CodeSource cs = pd.getCodeSource();1099if (cs == null)1100return perms;11011102CodeSource canonCodeSource = AccessController.doPrivileged(1103new java.security.PrivilegedAction<>(){1104@Override1105public CodeSource run() {1106return canonicalizeCodebase(cs, true);1107}1108});1109return getPermissions(perms, canonCodeSource, pd.getPrincipals());1110}11111112/**1113* Examines the global policy and returns the provided Permissions1114* object with additional permissions granted to the specified1115* CodeSource.1116*1117* @param perms the permissions to populate1118* @param cs the codesource associated with the caller.1119* This encapsulates the original location of the code (where the code1120* came from) and the public key(s) of its signer.1121*1122* @return the set of permissions according to the policy.1123*/1124private PermissionCollection getPermissions(Permissions perms,1125final CodeSource cs) {11261127if (cs == null)1128return perms;11291130CodeSource canonCodeSource = AccessController.doPrivileged(1131new PrivilegedAction<>(){1132@Override1133public CodeSource run() {1134return canonicalizeCodebase(cs, true);1135}1136});11371138return getPermissions(perms, canonCodeSource, null);1139}11401141private Permissions getPermissions(Permissions perms,1142final CodeSource cs,1143Principal[] principals) {1144for (PolicyEntry entry : policyInfo.policyEntries) {1145addPermissions(perms, cs, principals, entry);1146}11471148return perms;1149}11501151private void addPermissions(Permissions perms,1152final CodeSource cs,1153Principal[] principals,1154final PolicyEntry entry) {11551156if (debug != null) {1157debug.println("evaluate codesources:\n" +1158"\tPolicy CodeSource: " + entry.getCodeSource() + "\n" +1159"\tActive CodeSource: " + cs);1160}11611162// check to see if the CodeSource implies1163Boolean imp = AccessController.doPrivileged1164(new PrivilegedAction<>() {1165@Override1166public Boolean run() {1167return entry.getCodeSource().implies(cs);1168}1169});1170if (!imp.booleanValue()) {1171if (debug != null) {1172debug.println("evaluation (codesource) failed");1173}11741175// CodeSource does not imply - return and try next policy entry1176return;1177}11781179// check to see if the Principals imply11801181List<PolicyParser.PrincipalEntry> entryPs = entry.getPrincipals();1182if (debug != null) {1183List<PolicyParser.PrincipalEntry> accPs = new ArrayList<>();1184if (principals != null) {1185for (int i = 0; i < principals.length; i++) {1186accPs.add(new PolicyParser.PrincipalEntry1187(principals[i].getClass().getName(),1188principals[i].getName()));1189}1190}1191debug.println("evaluate principals:\n" +1192"\tPolicy Principals: " + entryPs + "\n" +1193"\tActive Principals: " + accPs);1194}11951196if (entryPs == null || entryPs.isEmpty()) {11971198// policy entry has no principals -1199// add perms regardless of principals in current ACC12001201addPerms(perms, principals, entry);1202if (debug != null) {1203debug.println("evaluation (codesource/principals) passed");1204}1205return;12061207} else if (principals == null || principals.length == 0) {12081209// current thread has no principals but this policy entry1210// has principals - perms are not added12111212if (debug != null) {1213debug.println("evaluation (principals) failed");1214}1215return;1216}12171218// current thread has principals and this policy entry1219// has principals. see if policy entry principals match1220// principals in current ACC12211222for (PolicyParser.PrincipalEntry pppe : entryPs) {12231224// Check for wildcards1225if (pppe.isWildcardClass()) {1226// a wildcard class matches all principals in current ACC1227continue;1228}12291230if (pppe.isWildcardName()) {1231// a wildcard name matches any principal with the same class1232if (wildcardPrincipalNameImplies(pppe.principalClass,1233principals)) {1234continue;1235}1236if (debug != null) {1237debug.println("evaluation (principal name wildcard) failed");1238}1239// policy entry principal not in current ACC -1240// immediately return and go to next policy entry1241return;1242}12431244Set<Principal> pSet = new HashSet<>(Arrays.asList(principals));1245Subject subject = new Subject(true, pSet,1246Collections.EMPTY_SET,1247Collections.EMPTY_SET);1248try {1249ClassLoader cl = Thread.currentThread().getContextClassLoader();1250Class<?> pClass = Class.forName(pppe.principalClass, false, cl);1251Principal p = getKnownPrincipal(pClass, pppe.principalName);1252if (p == null) {1253if (!Principal.class.isAssignableFrom(pClass)) {1254// not the right subtype1255throw new ClassCastException(pppe.principalClass +1256" is not a Principal");1257}12581259Constructor<?> c = pClass.getConstructor(PARAMS1);1260p = (Principal)c.newInstance(new Object[] {1261pppe.principalName });12621263}12641265if (debug != null) {1266debug.println("found Principal " + p.getClass().getName());1267}12681269// check if the Principal implies the current1270// thread's principals1271if (!p.implies(subject)) {1272if (debug != null) {1273debug.println("evaluation (principal implies) failed");1274}12751276// policy principal does not imply the current Subject -1277// immediately return and go to next policy entry1278return;1279}1280} catch (Exception e) {1281// fall back to default principal comparison.1282// see if policy entry principal is in current ACC12831284if (debug != null) {1285e.printStackTrace();1286}12871288if (!pppe.implies(subject)) {1289if (debug != null) {1290debug.println("evaluation (default principal implies) failed");1291}12921293// policy entry principal not in current ACC -1294// immediately return and go to next policy entry1295return;1296}1297}12981299// either the principal information matched,1300// or the Principal.implies succeeded.1301// continue loop and test the next policy principal1302}13031304// all policy entry principals were found in the current ACC -1305// grant the policy permissions13061307if (debug != null) {1308debug.println("evaluation (codesource/principals) passed");1309}1310addPerms(perms, principals, entry);1311}13121313/**1314* Returns true if the array of principals contains at least one1315* principal of the specified class.1316*/1317private static boolean wildcardPrincipalNameImplies(String principalClass,1318Principal[] principals)1319{1320for (Principal p : principals) {1321if (principalClass.equals(p.getClass().getName())) {1322return true;1323}1324}1325return false;1326}13271328private void addPerms(Permissions perms,1329Principal[] accPs,1330PolicyEntry entry) {1331for (int i = 0; i < entry.permissions.size(); i++) {1332Permission p = entry.permissions.get(i);1333if (debug != null) {1334debug.println(" granting " + p);1335}13361337if (p instanceof SelfPermission) {1338// handle "SELF" permissions1339expandSelf((SelfPermission)p,1340entry.getPrincipals(),1341accPs,1342perms);1343} else {1344perms.add(FilePermCompat.newPermPlusAltPath(p));1345}1346}1347}13481349/**1350* @param sp the SelfPermission that needs to be expanded.1351*1352* @param entryPs list of principals for the Policy entry.1353*1354* @param pdp Principal array from the current ProtectionDomain.1355*1356* @param perms the PermissionCollection where the individual1357* Permissions will be added after expansion.1358*/13591360private void expandSelf(SelfPermission sp,1361List<PolicyParser.PrincipalEntry> entryPs,1362Principal[] pdp,1363Permissions perms) {13641365if (entryPs == null || entryPs.isEmpty()) {1366// No principals in the grant to substitute1367if (debug != null) {1368debug.println("Ignoring permission "1369+ sp.getSelfType()1370+ " with target name ("1371+ sp.getSelfName() + "). "1372+ "No Principal(s) specified "1373+ "in the grant clause. "1374+ "SELF-based target names are "1375+ "only valid in the context "1376+ "of a Principal-based grant entry."1377);1378}1379return;1380}1381int startIndex = 0;1382int v;1383StringBuilder sb = new StringBuilder();1384while ((v = sp.getSelfName().indexOf(SELF, startIndex)) != -1) {13851386// add non-SELF string1387sb.append(sp.getSelfName().substring(startIndex, v));13881389// expand SELF1390Iterator<PolicyParser.PrincipalEntry> pli = entryPs.iterator();1391while (pli.hasNext()) {1392PolicyParser.PrincipalEntry pppe = pli.next();1393String[][] principalInfo = getPrincipalInfo(pppe,pdp);1394for (int i = 0; i < principalInfo.length; i++) {1395if (i != 0) {1396sb.append(", ");1397}1398sb.append(principalInfo[i][0] + " " +1399"\"" + principalInfo[i][1] + "\"");1400}1401if (pli.hasNext()) {1402sb.append(", ");1403}1404}1405startIndex = v + SELF.length();1406}1407// add remaining string (might be the entire string)1408sb.append(sp.getSelfName().substring(startIndex));14091410if (debug != null) {1411debug.println(" expanded:\n\t" + sp.getSelfName()1412+ "\n into:\n\t" + sb.toString());1413}1414try {1415// first try to instantiate the permission1416perms.add(FilePermCompat.newPermPlusAltPath(getInstance(sp.getSelfType(),1417sb.toString(),1418sp.getSelfActions())));1419} catch (ClassNotFoundException cnfe) {1420// ok, the permission is not in the bootclasspath.1421// before we add an UnresolvedPermission, check to see1422// whether this perm already belongs to the collection.1423// if so, use that perm's ClassLoader to create a new1424// one.1425Class<?> pc = null;1426synchronized (perms) {1427Enumeration<Permission> e = perms.elements();1428while (e.hasMoreElements()) {1429Permission pElement = e.nextElement();1430if (pElement.getClass().getName().equals(sp.getSelfType())) {1431pc = pElement.getClass();1432break;1433}1434}1435}1436if (pc == null) {1437// create an UnresolvedPermission1438perms.add(new UnresolvedPermission(sp.getSelfType(),1439sb.toString(),1440sp.getSelfActions(),1441sp.getCerts()));1442} else {1443try {1444// we found an instantiated permission.1445// use its class loader to instantiate a new permission.1446Constructor<?> c;1447// name parameter can not be null1448if (sp.getSelfActions() == null) {1449try {1450c = pc.getConstructor(PARAMS1);1451perms.add((Permission)c.newInstance1452(new Object[] {sb.toString()}));1453} catch (NoSuchMethodException ne) {1454c = pc.getConstructor(PARAMS2);1455perms.add((Permission)c.newInstance1456(new Object[] {sb.toString(),1457sp.getSelfActions() }));1458}1459} else {1460c = pc.getConstructor(PARAMS2);1461perms.add((Permission)c.newInstance1462(new Object[] {sb.toString(),1463sp.getSelfActions()}));1464}1465} catch (Exception nme) {1466if (debug != null) {1467debug.println("self entry expansion " +1468" instantiation failed: "1469+ nme.toString());1470}1471}1472}1473} catch (Exception e) {1474if (debug != null) {1475debug.println(e.toString());1476}1477}1478}14791480/**1481* return the principal class/name pair in the 2D array.1482* array[x][y]: x corresponds to the array length.1483* if (y == 0), it's the principal class.1484* if (y == 1), it's the principal name.1485*/1486private String[][] getPrincipalInfo1487(PolicyParser.PrincipalEntry pe, Principal[] pdp) {14881489// there are 3 possibilities:1490// 1) the entry's Principal class and name are not wildcarded1491// 2) the entry's Principal name is wildcarded only1492// 3) the entry's Principal class and name are wildcarded14931494if (!pe.isWildcardClass() && !pe.isWildcardName()) {14951496// build an info array for the principal1497// from the Policy entry1498String[][] info = new String[1][2];1499info[0][0] = pe.principalClass;1500info[0][1] = pe.principalName;1501return info;15021503} else if (!pe.isWildcardClass() && pe.isWildcardName()) {15041505// build an info array for every principal1506// in the current domain which has a principal class1507// that is equal to policy entry principal class name1508List<Principal> plist = new ArrayList<>();1509for (int i = 0; i < pdp.length; i++) {1510if (pe.principalClass.equals(pdp[i].getClass().getName()))1511plist.add(pdp[i]);1512}1513String[][] info = new String[plist.size()][2];1514int i = 0;1515for (Principal p : plist) {1516info[i][0] = p.getClass().getName();1517info[i][1] = p.getName();1518i++;1519}1520return info;15211522} else {15231524// build an info array for every1525// one of the current Domain's principals15261527String[][] info = new String[pdp.length][2];15281529for (int i = 0; i < pdp.length; i++) {1530info[i][0] = pdp[i].getClass().getName();1531info[i][1] = pdp[i].getName();1532}1533return info;1534}1535}15361537/*1538* Returns the signer certificates from the list of certificates1539* associated with the given code source.1540*1541* The signer certificates are those certificates that were used1542* to verify signed code originating from the codesource location.1543*1544* This method assumes that in the given code source, each signer1545* certificate is followed by its supporting certificate chain1546* (which may be empty), and that the signer certificate and its1547* supporting certificate chain are ordered bottom-to-top1548* (i.e., with the signer certificate first and the (root) certificate1549* authority last).1550*/1551protected Certificate[] getSignerCertificates(CodeSource cs) {1552Certificate[] certs = null;1553if ((certs = cs.getCertificates()) == null)1554return null;1555for (int i=0; i<certs.length; i++) {1556if (!(certs[i] instanceof X509Certificate))1557return cs.getCertificates();1558}15591560// Do we have to do anything?1561int i = 0;1562int count = 0;1563while (i < certs.length) {1564count++;1565while (((i+1) < certs.length)1566&& ((X509Certificate)certs[i]).getIssuerX500Principal().equals(1567((X509Certificate)certs[i+1]).getSubjectX500Principal())) {1568i++;1569}1570i++;1571}1572if (count == certs.length)1573// Done1574return certs;15751576List<Certificate> userCertList = new ArrayList<>();1577i = 0;1578while (i < certs.length) {1579userCertList.add(certs[i]);1580while (((i+1) < certs.length)1581&& ((X509Certificate)certs[i]).getIssuerX500Principal().equals(1582((X509Certificate)certs[i+1]).getSubjectX500Principal())) {1583i++;1584}1585i++;1586}1587Certificate[] userCerts = new Certificate[userCertList.size()];1588userCertList.toArray(userCerts);1589return userCerts;1590}15911592private CodeSource canonicalizeCodebase(CodeSource cs,1593boolean extractSignerCerts) {15941595String path = null;15961597CodeSource canonCs = cs;1598URL u = cs.getLocation();1599if (u != null) {1600if (u.getProtocol().equals("jar")) {1601// unwrap url embedded inside jar url1602String spec = u.getFile();1603int separator = spec.indexOf("!/");1604if (separator != -1) {1605try {1606u = new URL(spec.substring(0, separator));1607} catch (MalformedURLException e) {1608// Fail silently. In this case, url stays what1609// it was above1610}1611}1612}1613if (u.getProtocol().equals("file")) {1614boolean isLocalFile = false;1615String host = u.getHost();1616isLocalFile = (host == null || host.isEmpty() ||1617host.equals("~") || host.equalsIgnoreCase("localhost"));16181619if (isLocalFile) {1620path = u.getFile().replace('/', File.separatorChar);1621path = ParseUtil.decode(path);1622}1623}1624}16251626if (path != null) {1627try {1628URL csUrl = null;1629path = canonPath(path);1630csUrl = ParseUtil.fileToEncodedURL(new File(path));16311632if (extractSignerCerts) {1633canonCs = new CodeSource(csUrl,1634getSignerCertificates(cs));1635} else {1636canonCs = new CodeSource(csUrl,1637cs.getCertificates());1638}1639} catch (IOException ioe) {1640// leave codesource as it is, unless we have to extract its1641// signer certificates1642if (extractSignerCerts) {1643canonCs = new CodeSource(cs.getLocation(),1644getSignerCertificates(cs));1645}1646}1647} else {1648if (extractSignerCerts) {1649canonCs = new CodeSource(cs.getLocation(),1650getSignerCertificates(cs));1651}1652}1653return canonCs;1654}16551656// Wrapper to return a canonical path that avoids calling getCanonicalPath()1657// with paths that are intended to match all entries in the directory1658private static String canonPath(String path) throws IOException {1659if (path.endsWith("*")) {1660path = path.substring(0, path.length()-1) + "-";1661path = new File(path).getCanonicalPath();1662return path.substring(0, path.length()-1) + "*";1663} else {1664return new File(path).getCanonicalPath();1665}1666}16671668private String printPD(ProtectionDomain pd) {1669Principal[] principals = pd.getPrincipals();1670String pals = "<no principals>";1671if (principals != null && principals.length > 0) {1672StringBuilder palBuf = new StringBuilder("(principals ");1673for (int i = 0; i < principals.length; i++) {1674palBuf.append(principals[i].getClass().getName() +1675" \"" + principals[i].getName() +1676"\"");1677if (i < principals.length-1)1678palBuf.append(", ");1679else1680palBuf.append(")");1681}1682pals = palBuf.toString();1683}1684return "PD CodeSource: "1685+ pd.getCodeSource()1686+"\n\t" + "PD ClassLoader: "1687+ pd.getClassLoader()1688+"\n\t" + "PD Principals: "1689+ pals;1690}16911692/**1693* return true if no replacement was performed,1694* or if replacement succeeded.1695*/1696private boolean replacePrincipals(1697List<PolicyParser.PrincipalEntry> principals, KeyStore keystore) {16981699if (principals == null || principals.isEmpty() || keystore == null)1700return true;17011702for (PolicyParser.PrincipalEntry pppe : principals) {1703if (pppe.isReplaceName()) {17041705// perform replacement1706// (only X509 replacement is possible now)1707String name;1708if ((name = getDN(pppe.principalName, keystore)) == null) {1709return false;1710}17111712if (debug != null) {1713debug.println(" Replacing \"" +1714pppe.principalName +1715"\" with " +1716X500PRINCIPAL + "/\"" +1717name +1718"\"");1719}17201721pppe.principalClass = X500PRINCIPAL;1722pppe.principalName = name;1723}1724}1725// return true if no replacement was performed,1726// or if replacement succeeded1727return true;1728}17291730private void expandPermissionName(PolicyParser.PermissionEntry pe,1731KeyStore keystore) throws Exception {1732// short cut the common case1733if (pe.name == null || pe.name.indexOf("${{", 0) == -1) {1734return;1735}17361737int startIndex = 0;1738int b, e;1739StringBuilder sb = new StringBuilder();1740while ((b = pe.name.indexOf("${{", startIndex)) != -1) {1741e = pe.name.indexOf("}}", b);1742if (e < 1) {1743break;1744}1745sb.append(pe.name.substring(startIndex, b));17461747// get the value in ${{...}}1748String value = pe.name.substring(b+3, e);17491750// parse up to the first ':'1751int colonIndex;1752String prefix = value;1753String suffix;1754if ((colonIndex = value.indexOf(':')) != -1) {1755prefix = value.substring(0, colonIndex);1756}17571758// handle different prefix possibilities1759if (prefix.equalsIgnoreCase("self")) {1760// do nothing - handled later1761sb.append(pe.name.substring(b, e+2));1762startIndex = e+2;1763continue;1764} else if (prefix.equalsIgnoreCase("alias")) {1765// get the suffix and perform keystore alias replacement1766if (colonIndex == -1) {1767Object[] source = {pe.name};1768throw new Exception(1769LocalizedMessage.getNonlocalized(1770"alias.name.not.provided.pe.name.",1771source));1772}1773suffix = value.substring(colonIndex+1);1774if ((suffix = getDN(suffix, keystore)) == null) {1775Object[] source = {value.substring(colonIndex+1)};1776throw new Exception(1777LocalizedMessage.getNonlocalized(1778"unable.to.perform.substitution.on.alias.suffix",1779source));1780}17811782sb.append(X500PRINCIPAL + " \"" + suffix + "\"");1783startIndex = e+2;1784} else {1785Object[] source = {prefix};1786throw new Exception(1787LocalizedMessage.getNonlocalized(1788"substitution.value.prefix.unsupported",1789source));1790}1791}17921793// copy the rest of the value1794sb.append(pe.name.substring(startIndex));17951796// replace the name with expanded value1797if (debug != null) {1798debug.println(" Permission name expanded from:\n\t" +1799pe.name + "\nto\n\t" + sb.toString());1800}1801pe.name = sb.toString();1802}18031804private String getDN(String alias, KeyStore keystore) {1805Certificate cert = null;1806try {1807cert = keystore.getCertificate(alias);1808} catch (Exception e) {1809if (debug != null) {1810debug.println(" Error retrieving certificate for '" +1811alias +1812"': " +1813e.toString());1814}1815return null;1816}18171818if (cert == null || !(cert instanceof X509Certificate)) {1819if (debug != null) {1820debug.println(" -- No certificate for '" +1821alias +1822"' - ignoring entry");1823}1824return null;1825} else {1826X509Certificate x509Cert = (X509Certificate)cert;18271828// 4702543: X500 names with an EmailAddress1829// were encoded incorrectly. create new1830// X500Principal name with correct encoding18311832X500Principal p = new X500Principal1833(x509Cert.getSubjectX500Principal().toString());1834return p.getName();1835}1836}18371838/**1839* Each entry in the policy configuration file is represented by a1840* PolicyEntry object. <p>1841*1842* A PolicyEntry is a (CodeSource,Permission) pair. The1843* CodeSource contains the (URL, PublicKey) that together identify1844* where the Java bytecodes come from and who (if anyone) signed1845* them. The URL could refer to localhost. The URL could also be1846* null, meaning that this policy entry is given to all comers, as1847* long as they match the signer field. The signer could be null,1848* meaning the code is not signed. <p>1849*1850* The Permission contains the (Type, Name, Action) triplet. <p>1851*1852* For now, the Policy object retrieves the public key from the1853* X.509 certificate on disk that corresponds to the signedBy1854* alias specified in the Policy config file. For reasons of1855* efficiency, the Policy object keeps a hashtable of certs already1856* read in. This could be replaced by a secure internal key1857* store.1858*1859* <p>1860* For example, the entry1861* <pre>1862* permission java.io.File "/tmp", "read,write",1863* signedBy "Duke";1864* </pre>1865* is represented internally1866* <pre>1867*1868* FilePermission f = new FilePermission("/tmp", "read,write");1869* PublicKey p = publickeys.get("Duke");1870* URL u = InetAddress.getLocalHost();1871* CodeBase c = new CodeBase( p, u );1872* pe = new PolicyEntry(f, c);1873* </pre>1874*1875* @author Marianne Mueller1876* @author Roland Schemers1877* @see java.security.CodeSource1878* @see java.security.Policy1879* @see java.security.Permissions1880* @see java.security.ProtectionDomain1881*/1882private static class PolicyEntry {18831884private final CodeSource codesource;1885final List<Permission> permissions;1886private final List<PolicyParser.PrincipalEntry> principals;18871888/**1889* Given a Permission and a CodeSource, create a policy entry.1890*1891* XXX Decide if/how to add validity fields and "purpose" fields to1892* XXX policy entries1893*1894* @param cs the CodeSource, which encapsulates the URL and the1895* public key1896* attributes from the policy config file. Validity checks1897* are performed on the public key before PolicyEntry is1898* called.1899*1900*/1901PolicyEntry(CodeSource cs, List<PolicyParser.PrincipalEntry> principals)1902{1903this.codesource = cs;1904this.permissions = new ArrayList<Permission>();1905this.principals = principals; // can be null1906}19071908PolicyEntry(CodeSource cs)1909{1910this(cs, null);1911}19121913List<PolicyParser.PrincipalEntry> getPrincipals() {1914return principals; // can be null1915}19161917/**1918* add a Permission object to this entry.1919* No need to sync add op because perms are added to entry only1920* while entry is being initialized1921*/1922void add(Permission p) {1923permissions.add(p);1924}19251926/**1927* Return the CodeSource for this policy entry1928*/1929CodeSource getCodeSource() {1930return codesource;1931}19321933@Override public String toString(){1934StringBuilder sb = new StringBuilder();1935sb.append(ResourcesMgr.getString("LPARAM"));1936sb.append(getCodeSource());1937sb.append("\n");1938for (int j = 0; j < permissions.size(); j++) {1939Permission p = permissions.get(j);1940sb.append(ResourcesMgr.getString("SPACE"));1941sb.append(ResourcesMgr.getString("SPACE"));1942sb.append(p);1943sb.append(ResourcesMgr.getString("NEWLINE"));1944}1945sb.append(ResourcesMgr.getString("RPARAM"));1946sb.append(ResourcesMgr.getString("NEWLINE"));1947return sb.toString();1948}1949}19501951private static class SelfPermission extends Permission {19521953@java.io.Serial1954private static final long serialVersionUID = -8315562579967246806L;19551956/**1957* The class name of the Permission class that will be1958* created when this self permission is expanded .1959*1960* @serial1961*/1962private String type;19631964/**1965* The permission name.1966*1967* @serial1968*/1969private String name;19701971/**1972* The actions of the permission.1973*1974* @serial1975*/1976private String actions;19771978/**1979* The certs of the permission.1980*1981* @serial1982*/1983private Certificate[] certs;19841985/**1986* Creates a new SelfPermission containing the permission1987* information needed later to expand the self1988* @param type the class name of the Permission class that will be1989* created when this permission is expanded and if necessary resolved.1990* @param name the name of the permission.1991* @param actions the actions of the permission.1992* @param certs the certificates the permission's class was signed with.1993* This is a list of certificate chains, where each chain is composed of1994* a signer certificate and optionally its supporting certificate chain.1995* Each chain is ordered bottom-to-top (i.e., with the signer1996* certificate first and the (root) certificate authority last).1997*/1998public SelfPermission(String type, String name, String actions,1999Certificate[] certs)2000{2001super(type);2002if (type == null) {2003throw new NullPointerException2004(LocalizedMessage.getNonlocalized("type.can.t.be.null"));2005}2006this.type = type;2007this.name = name;2008this.actions = actions;2009if (certs != null) {2010// Extract the signer certs from the list of certificates.2011for (int i=0; i<certs.length; i++) {2012if (!(certs[i] instanceof X509Certificate)) {2013// there is no concept of signer certs, so we store the2014// entire cert array2015this.certs = certs.clone();2016break;2017}2018}20192020if (this.certs == null) {2021// Go through the list of certs and see if all the certs are2022// signer certs.2023int i = 0;2024int count = 0;2025while (i < certs.length) {2026count++;2027while (((i+1) < certs.length) &&2028((X509Certificate)certs[i]).getIssuerX500Principal().equals(2029((X509Certificate)certs[i+1]).getSubjectX500Principal())) {2030i++;2031}2032i++;2033}2034if (count == certs.length) {2035// All the certs are signer certs, so we store the2036// entire array2037this.certs = certs.clone();2038}20392040if (this.certs == null) {2041// extract the signer certs2042List<Certificate> signerCerts = new ArrayList<>();2043i = 0;2044while (i < certs.length) {2045signerCerts.add(certs[i]);2046while (((i+1) < certs.length) &&2047((X509Certificate)certs[i]).getIssuerX500Principal().equals(2048((X509Certificate)certs[i+1]).getSubjectX500Principal())) {2049i++;2050}2051i++;2052}2053this.certs = new Certificate[signerCerts.size()];2054signerCerts.toArray(this.certs);2055}2056}2057}2058}20592060/**2061* This method always returns false for SelfPermission permissions.2062* That is, an SelfPermission never considered to2063* imply another permission.2064*2065* @param p the permission to check against.2066*2067* @return false.2068*/2069@Override public boolean implies(Permission p) {2070return false;2071}20722073/**2074* Checks two SelfPermission objects for equality.2075*2076* Checks that <i>obj</i> is an SelfPermission, and has2077* the same type (class) name, permission name, actions, and2078* certificates as this object.2079*2080* @param obj the object we are testing for equality with this object.2081*2082* @return true if obj is an SelfPermission, and has the same2083* type (class) name, permission name, actions, and2084* certificates as this object.2085*/2086@Override public boolean equals(Object obj) {2087if (obj == this)2088return true;20892090if (! (obj instanceof SelfPermission))2091return false;2092SelfPermission that = (SelfPermission) obj;20932094if (!(this.type.equals(that.type) &&2095this.name.equals(that.name) &&2096this.actions.equals(that.actions)))2097return false;20982099if (this.certs.length != that.certs.length)2100return false;21012102int i,j;2103boolean match;21042105for (i = 0; i < this.certs.length; i++) {2106match = false;2107for (j = 0; j < that.certs.length; j++) {2108if (this.certs[i].equals(that.certs[j])) {2109match = true;2110break;2111}2112}2113if (!match) return false;2114}21152116for (i = 0; i < that.certs.length; i++) {2117match = false;2118for (j = 0; j < this.certs.length; j++) {2119if (that.certs[i].equals(this.certs[j])) {2120match = true;2121break;2122}2123}2124if (!match) return false;2125}2126return true;2127}21282129/**2130* Returns the hash code value for this object.2131*2132* @return a hash code value for this object.2133*/2134@Override public int hashCode() {2135int hash = type.hashCode();2136if (name != null)2137hash ^= name.hashCode();2138if (actions != null)2139hash ^= actions.hashCode();2140return hash;2141}21422143/**2144* Returns the canonical string representation of the actions,2145* which currently is the empty string "", since there are no actions2146* for an SelfPermission. That is, the actions for the2147* permission that will be created when this SelfPermission2148* is resolved may be non-null, but an SelfPermission2149* itself is never considered to have any actions.2150*2151* @return the empty string "".2152*/2153@Override public String getActions() {2154return "";2155}21562157public String getSelfType() {2158return type;2159}21602161public String getSelfName() {2162return name;2163}21642165public String getSelfActions() {2166return actions;2167}21682169public Certificate[] getCerts() {2170return certs;2171}21722173/**2174* Returns a string describing this SelfPermission. The convention2175* is to specify the class name, the permission name, and the actions,2176* in the following format: '(unresolved "ClassName" "name" "actions")'.2177*2178* @return information about this SelfPermission.2179*/2180@Override public String toString() {2181return "(SelfPermission " + type + " " + name + " " + actions + ")";2182}2183}21842185/**2186* holds policy information that we need to synch on2187*/2188private static class PolicyInfo {2189private static final boolean verbose = false;21902191// Stores grant entries in the policy2192final List<PolicyEntry> policyEntries;21932194// Maps aliases to certs2195final Map<Object, Object> aliasMapping;21962197// Maps ProtectionDomain to PermissionCollection2198private final ProtectionDomainCache[] pdMapping;2199private java.util.Random random;22002201PolicyInfo(int numCaches) {2202policyEntries = new ArrayList<>();2203aliasMapping = Collections.synchronizedMap(new HashMap<>(11));22042205pdMapping = new ProtectionDomainCache[numCaches];2206JavaSecurityAccess jspda2207= SharedSecrets.getJavaSecurityAccess();2208for (int i = 0; i < numCaches; i++) {2209pdMapping[i] = jspda.getProtectionDomainCache();2210}2211if (numCaches > 1) {2212random = new java.util.Random();2213}2214}2215ProtectionDomainCache getPdMapping() {2216if (pdMapping.length == 1) {2217return pdMapping[0];2218} else {2219int i = java.lang.Math.abs(random.nextInt() % pdMapping.length);2220return pdMapping[i];2221}2222}2223}2224}222522262227