Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/security/provider/PolicyFile.java
41159 views
1
/*
2
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.security.provider;
27
28
import java.io.*;
29
import java.lang.reflect.*;
30
import java.net.MalformedURLException;
31
import java.net.URL;
32
import java.net.URI;
33
import java.nio.file.Files;
34
import java.nio.file.Path;
35
import java.util.*;
36
import java.security.*;
37
import java.security.cert.Certificate;
38
import java.security.cert.X509Certificate;
39
import javax.security.auth.Subject;
40
import javax.security.auth.x500.X500Principal;
41
import java.net.SocketPermission;
42
import java.net.NetPermission;
43
import java.util.concurrent.ConcurrentHashMap;
44
import jdk.internal.access.JavaSecurityAccess;
45
import jdk.internal.access.SharedSecrets;
46
import jdk.internal.util.StaticProperty;
47
import sun.security.util.*;
48
import sun.net.www.ParseUtil;
49
50
import static java.nio.charset.StandardCharsets.UTF_8;
51
import static jdk.internal.access.JavaSecurityAccess.ProtectionDomainCache;
52
53
/**
54
* This class represents a default Policy implementation for the
55
* "JavaPolicy" type.
56
*
57
* <p> This object stores the policy for the entire Java runtime,
58
* and is the amalgamation of multiple static policy
59
* configurations that resides in files.
60
* The algorithm for locating the policy file(s) and reading their
61
* information into this <code>Policy</code> object is:
62
*
63
* <ol>
64
* <li>
65
* Read in and load the default policy file named
66
* &lt;JAVA_HOME&gt;/lib/security/default.policy. &lt;JAVA_HOME&gt; refers
67
* to the value of the java.home system property, and specifies the directory
68
* where the JRE is installed. This policy file grants permissions to the
69
* modules loaded by the platform class loader. If the default policy file
70
* cannot be loaded, a fatal InternalError is thrown as these permissions
71
* 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 set
76
* in the Java security properties file, which is located in the file named
77
* &lt;JAVA_HOME&gt;/conf/security/java.security.
78
* Each property value specifies a <code>URL</code> pointing to a
79
* policy file to be loaded. Read in and load each policy.
80
*
81
* If none of these could be loaded, use a builtin static policy
82
* 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 file
87
* (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 the
89
* 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 using
94
* "==" (rather than "="), then load the specified policy file and ignore
95
* all other configured policies. Note, that the default.policy file is
96
* 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 policy
98
* equivalent to the default conf/security/java.policy file.
99
* </ol>
100
*
101
* Each policy file consists of one or more grant entries, each of
102
* 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 case
119
* 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 match
130
* any <code>Principal</code> class. In addition, the <i>principalName</i>
131
* may also be set to the wildcard value, *, allowing it to match
132
* 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 is
137
* 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 for
141
* 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 as
144
* <code>java.lang.RuntimePermission</code>
145
* where it is not necessary - you either have the
146
* 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 entry
150
* is optional. If present, it indicates a signed permission. That is,
151
* the permission class itself must be signed by the given alias in
152
* 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 the
162
* <code>Foo.class</code> permission has been signed by the
163
* "FooSoft" alias, or if XXX <code>Foo.class</code> is a
164
* system class (i.e., is found on the CLASSPATH).
165
*
166
* <p> Items that appear in an entry must appear in the specified order
167
* (<code>permission</code>, <i>Type</i>, "<i>name</i>", and
168
* "<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 is
172
* 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 is
176
* <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 read
185
* // 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 any
193
* permission that contains the string, "<b>${{self}}</b>", as part of
194
* its target name. When such a permission is evaluated
195
* (such as during a security check), <b>${{self}}</b> is replaced
196
* with one or more Principal class/name pairs. The exact
197
* replacement performed depends upon the contents of the
198
* 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 containing
203
* <b>${{self}}</b> in their target names are only valid in the context
204
* of a principal-based grant clause). For example, BarPermission
205
* 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 by
216
* <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 grant
226
* clause, then <b>${{self}}</b> will be replaced by the same
227
* comma-separated list or principals.
228
* In the case where both the principal class and name are
229
* wildcarded in the grant clause, <b>${{self}}</b> is replaced
230
* 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>" is
235
* deprecated in favour of "<b>${{self}}</b>".
236
*
237
* @see java.security.CodeSource
238
* @see java.security.Permissions
239
* @see java.security.ProtectionDomain
240
*/
241
@SuppressWarnings("removal")
242
public class PolicyFile extends java.security.Policy {
243
244
private static final Debug debug = Debug.getInstance("policy");
245
246
private static final String SELF = "${{self}}";
247
private static final String X500PRINCIPAL =
248
"javax.security.auth.x500.X500Principal";
249
private static final String POLICY = "java.security.policy";
250
private static final String POLICY_URL = "policy.url.";
251
252
private static final int DEFAULT_CACHE_SIZE = 1;
253
254
// contains the policy grant entries, PD cache, and alias mapping
255
// can be updated if refresh() is called
256
private volatile PolicyInfo policyInfo;
257
258
private boolean expandProperties = true;
259
private boolean allowSystemProperties = true;
260
private boolean notUtf8 = false;
261
private URL url;
262
263
// for use with the reflection API
264
private static final Class<?>[] PARAMS0 = { };
265
private static final Class<?>[] PARAMS1 = { String.class };
266
private static final Class<?>[] PARAMS2 = { String.class, String.class };
267
268
/**
269
* When a policy file has a syntax error, the exception code may generate
270
* another permission check and this can cause the policy file to be parsed
271
* repeatedly, leading to a StackOverflowError or ClassCircularityError.
272
* To avoid this, this set is populated with policy files that have been
273
* previously parsed and have syntax errors, so that they can be
274
* subsequently ignored.
275
*/
276
private static Set<URL> badPolicyURLs =
277
Collections.newSetFromMap(new ConcurrentHashMap<URL,Boolean>());
278
279
/**
280
* Initializes the Policy object and reads the default policy
281
* configuration file(s) into the Policy object.
282
*/
283
public PolicyFile() {
284
init((URL)null);
285
}
286
287
/**
288
* Initializes the Policy object and reads the default policy
289
* from the specified URL only.
290
*/
291
public PolicyFile(URL url) {
292
this.url = url;
293
init(url);
294
}
295
296
/**
297
* Initializes the Policy object and reads the default policy
298
* configuration file(s) into the Policy object.
299
*
300
* See the class description for details on the algorithm used to
301
* initialize the Policy object.
302
*/
303
private void init(URL url) {
304
// Properties are set once for each init(); ignore changes
305
// between diff invocations of initPolicyFile(policy, url, info).
306
String numCacheStr =
307
AccessController.doPrivileged(new PrivilegedAction<>() {
308
@Override
309
public String run() {
310
expandProperties = "true".equalsIgnoreCase
311
(Security.getProperty("policy.expandProperties"));
312
allowSystemProperties = "true".equalsIgnoreCase
313
(Security.getProperty("policy.allowSystemProperty"));
314
notUtf8 = "false".equalsIgnoreCase
315
(System.getProperty("sun.security.policy.utf8"));
316
return System.getProperty("sun.security.policy.numcaches");
317
}});
318
319
int numCaches;
320
if (numCacheStr != null) {
321
try {
322
numCaches = Integer.parseInt(numCacheStr);
323
} catch (NumberFormatException e) {
324
numCaches = DEFAULT_CACHE_SIZE;
325
}
326
} else {
327
numCaches = DEFAULT_CACHE_SIZE;
328
}
329
PolicyInfo newInfo = new PolicyInfo(numCaches);
330
initPolicyFile(newInfo, url);
331
policyInfo = newInfo;
332
}
333
334
private void initPolicyFile(final PolicyInfo newInfo, final URL url) {
335
336
// always load default.policy
337
AccessController.doPrivileged(new PrivilegedAction<>() {
338
@Override
339
public Void run() {
340
initDefaultPolicy(newInfo);
341
return null;
342
}
343
});
344
345
if (url != null) {
346
347
/**
348
* If the caller specified a URL via Policy.getInstance,
349
* we only read from default.policy and that URL.
350
*/
351
352
if (debug != null) {
353
debug.println("reading " + url);
354
}
355
AccessController.doPrivileged(new PrivilegedAction<>() {
356
@Override
357
public Void run() {
358
if (init(url, newInfo) == false) {
359
// use static policy if all else fails
360
initStaticPolicy(newInfo);
361
}
362
return null;
363
}
364
});
365
366
} else {
367
368
/**
369
* Caller did not specify URL via Policy.getInstance.
370
* Read from URLs listed in the java.security properties file.
371
*/
372
373
boolean loaded_one = initPolicyFile(POLICY, POLICY_URL, newInfo);
374
// To maintain strict backward compatibility
375
// we load the static policy only if POLICY load failed
376
if (!loaded_one) {
377
// use static policy if all else fails
378
initStaticPolicy(newInfo);
379
}
380
}
381
}
382
383
private boolean initPolicyFile(final String propname, final String urlname,
384
final PolicyInfo newInfo) {
385
boolean loadedPolicy =
386
AccessController.doPrivileged(new PrivilegedAction<>() {
387
@Override
388
public Boolean run() {
389
boolean loaded_policy = false;
390
391
if (allowSystemProperties) {
392
String extra_policy = System.getProperty(propname);
393
if (extra_policy != null) {
394
boolean overrideAll = false;
395
if (extra_policy.startsWith("=")) {
396
overrideAll = true;
397
extra_policy = extra_policy.substring(1);
398
}
399
try {
400
extra_policy =
401
PropertyExpander.expand(extra_policy);
402
URL policyURL;
403
404
File policyFile = new File(extra_policy);
405
if (policyFile.exists()) {
406
policyURL = ParseUtil.fileToEncodedURL
407
(new File(policyFile.getCanonicalPath()));
408
} else {
409
policyURL = new URL(extra_policy);
410
}
411
if (debug != null) {
412
debug.println("reading "+policyURL);
413
}
414
if (init(policyURL, newInfo)) {
415
loaded_policy = true;
416
}
417
} catch (Exception e) {
418
// ignore.
419
if (debug != null) {
420
debug.println("caught exception: "+e);
421
}
422
}
423
if (overrideAll) {
424
if (debug != null) {
425
debug.println("overriding other policies!");
426
}
427
return Boolean.valueOf(loaded_policy);
428
}
429
}
430
}
431
432
int n = 1;
433
String policy_uri;
434
435
while ((policy_uri = Security.getProperty(urlname+n)) != null) {
436
try {
437
URL policy_url = null;
438
String expanded_uri = PropertyExpander.expand
439
(policy_uri).replace(File.separatorChar, '/');
440
441
if (policy_uri.startsWith("file:${java.home}/") ||
442
policy_uri.startsWith("file:${user.home}/")) {
443
444
// this special case accommodates
445
// the situation java.home/user.home
446
// expand to a single slash, resulting in
447
// a file://foo URI
448
policy_url = new File
449
(expanded_uri.substring(5)).toURI().toURL();
450
} else {
451
policy_url = new URI(expanded_uri).toURL();
452
}
453
454
if (debug != null) {
455
debug.println("reading " + policy_url);
456
}
457
if (init(policy_url, newInfo)) {
458
loaded_policy = true;
459
}
460
} catch (Exception e) {
461
if (debug != null) {
462
debug.println(
463
"Debug info only. Error reading policy " +e);
464
e.printStackTrace();
465
}
466
// ignore that policy
467
}
468
n++;
469
}
470
return Boolean.valueOf(loaded_policy);
471
}
472
});
473
474
return loadedPolicy;
475
}
476
477
private void initDefaultPolicy(PolicyInfo newInfo) {
478
Path defaultPolicy = Path.of(StaticProperty.javaHome(),
479
"lib",
480
"security",
481
"default.policy");
482
if (debug != null) {
483
debug.println("reading " + defaultPolicy);
484
}
485
try (BufferedReader br = Files.newBufferedReader(defaultPolicy)) {
486
487
PolicyParser pp = new PolicyParser(expandProperties);
488
pp.read(br);
489
490
Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
491
while (enum_.hasMoreElements()) {
492
PolicyParser.GrantEntry ge = enum_.nextElement();
493
addGrantEntry(ge, null, newInfo);
494
}
495
} catch (Exception e) {
496
throw new InternalError("Failed to load default.policy", e);
497
}
498
}
499
500
/**
501
* Reads a policy configuration into the Policy object using a
502
* Reader object.
503
*/
504
private boolean init(URL policy, PolicyInfo newInfo) {
505
506
// skip parsing policy file if it has been previously parsed and
507
// has syntax errors
508
if (badPolicyURLs.contains(policy)) {
509
if (debug != null) {
510
debug.println("skipping bad policy file: " + policy);
511
}
512
return false;
513
}
514
515
try (InputStreamReader isr =
516
getInputStreamReader(PolicyUtil.getInputStream(policy))) {
517
518
PolicyParser pp = new PolicyParser(expandProperties);
519
pp.read(isr);
520
521
KeyStore keyStore = null;
522
try {
523
keyStore = PolicyUtil.getKeyStore
524
(policy,
525
pp.getKeyStoreUrl(),
526
pp.getKeyStoreType(),
527
pp.getKeyStoreProvider(),
528
pp.getStorePassURL(),
529
debug);
530
} catch (Exception e) {
531
// ignore, treat it like we have no keystore
532
if (debug != null) {
533
debug.println("Debug info only. Ignoring exception.");
534
e.printStackTrace();
535
}
536
}
537
538
Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
539
while (enum_.hasMoreElements()) {
540
PolicyParser.GrantEntry ge = enum_.nextElement();
541
addGrantEntry(ge, keyStore, newInfo);
542
}
543
return true;
544
} catch (PolicyParser.ParsingException pe) {
545
// record bad policy file to avoid later reparsing it
546
badPolicyURLs.add(policy);
547
Object[] source = {policy, pe.getNonlocalizedMessage()};
548
System.err.println(LocalizedMessage.getNonlocalized
549
(POLICY + ".error.parsing.policy.message", source));
550
if (debug != null) {
551
pe.printStackTrace();
552
}
553
} catch (Exception e) {
554
if (debug != null) {
555
debug.println("error parsing "+policy);
556
debug.println(e.toString());
557
e.printStackTrace();
558
}
559
}
560
561
return false;
562
}
563
564
private InputStreamReader getInputStreamReader(InputStream is) {
565
/*
566
* Read in policy using UTF-8 by default.
567
*
568
* Check non-standard system property to see if the default encoding
569
* should be used instead.
570
*/
571
return (notUtf8)
572
? new InputStreamReader(is)
573
: new InputStreamReader(is, UTF_8);
574
}
575
576
private void initStaticPolicy(final PolicyInfo newInfo) {
577
if (debug != null) {
578
debug.println("Initializing with static permissions");
579
}
580
AccessController.doPrivileged(new PrivilegedAction<>() {
581
@Override
582
public Void run() {
583
PolicyEntry pe = new PolicyEntry(new CodeSource(null,
584
(Certificate[]) null));
585
pe.add(SecurityConstants.LOCAL_LISTEN_PERMISSION);
586
pe.add(new PropertyPermission("java.version",
587
SecurityConstants.PROPERTY_READ_ACTION));
588
pe.add(new PropertyPermission("java.vendor",
589
SecurityConstants.PROPERTY_READ_ACTION));
590
pe.add(new PropertyPermission("java.vendor.url",
591
SecurityConstants.PROPERTY_READ_ACTION));
592
pe.add(new PropertyPermission("java.class.version",
593
SecurityConstants.PROPERTY_READ_ACTION));
594
pe.add(new PropertyPermission("os.name",
595
SecurityConstants.PROPERTY_READ_ACTION));
596
pe.add(new PropertyPermission("os.version",
597
SecurityConstants.PROPERTY_READ_ACTION));
598
pe.add(new PropertyPermission("os.arch",
599
SecurityConstants.PROPERTY_READ_ACTION));
600
pe.add(new PropertyPermission("file.separator",
601
SecurityConstants.PROPERTY_READ_ACTION));
602
pe.add(new PropertyPermission("path.separator",
603
SecurityConstants.PROPERTY_READ_ACTION));
604
pe.add(new PropertyPermission("line.separator",
605
SecurityConstants.PROPERTY_READ_ACTION));
606
pe.add(new PropertyPermission
607
("java.specification.version",
608
SecurityConstants.PROPERTY_READ_ACTION));
609
pe.add(new PropertyPermission
610
("java.specification.vendor",
611
SecurityConstants.PROPERTY_READ_ACTION));
612
pe.add(new PropertyPermission
613
("java.specification.name",
614
SecurityConstants.PROPERTY_READ_ACTION));
615
pe.add(new PropertyPermission
616
("java.vm.specification.version",
617
SecurityConstants.PROPERTY_READ_ACTION));
618
pe.add(new PropertyPermission
619
("java.vm.specification.vendor",
620
SecurityConstants.PROPERTY_READ_ACTION));
621
pe.add(new PropertyPermission
622
("java.vm.specification.name",
623
SecurityConstants.PROPERTY_READ_ACTION));
624
pe.add(new PropertyPermission("java.vm.version",
625
SecurityConstants.PROPERTY_READ_ACTION));
626
pe.add(new PropertyPermission("java.vm.vendor",
627
SecurityConstants.PROPERTY_READ_ACTION));
628
pe.add(new PropertyPermission("java.vm.name",
629
SecurityConstants.PROPERTY_READ_ACTION));
630
631
// No need to sync because noone has access to newInfo yet
632
newInfo.policyEntries.add(pe);
633
634
return null;
635
}
636
});
637
}
638
639
/**
640
* Given a GrantEntry, create a codeSource.
641
*
642
* @return null if signedBy alias is not recognized
643
*/
644
private CodeSource getCodeSource(PolicyParser.GrantEntry ge, KeyStore keyStore,
645
PolicyInfo newInfo) throws java.net.MalformedURLException
646
{
647
Certificate[] certs = null;
648
if (ge.signedBy != null) {
649
certs = getCertificates(keyStore, ge.signedBy, newInfo);
650
if (certs == null) {
651
// we don't have a key for this alias,
652
// just return
653
if (debug != null) {
654
debug.println(" -- No certs for alias '" +
655
ge.signedBy + "' - ignoring entry");
656
}
657
return null;
658
}
659
}
660
661
URL location;
662
663
if (ge.codeBase != null)
664
location = new URL(ge.codeBase);
665
else
666
location = null;
667
668
return (canonicalizeCodebase(new CodeSource(location, certs),false));
669
}
670
671
/**
672
* Add one policy entry to the list.
673
*/
674
private void addGrantEntry(PolicyParser.GrantEntry ge,
675
KeyStore keyStore, PolicyInfo newInfo) {
676
677
if (debug != null) {
678
debug.println("Adding policy entry: ");
679
debug.println(" signedBy " + ge.signedBy);
680
debug.println(" codeBase " + ge.codeBase);
681
if (ge.principals != null) {
682
for (PolicyParser.PrincipalEntry pppe : ge.principals) {
683
debug.println(" " + pppe.toString());
684
}
685
}
686
}
687
688
try {
689
CodeSource codesource = getCodeSource(ge, keyStore, newInfo);
690
// skip if signedBy alias was unknown...
691
if (codesource == null) return;
692
693
// perform keystore alias principal replacement.
694
// for example, if alias resolves to X509 certificate,
695
// replace principal with: <X500Principal class> <SubjectDN>
696
// -- skip if alias is unknown
697
if (replacePrincipals(ge.principals, keyStore) == false)
698
return;
699
PolicyEntry entry = new PolicyEntry(codesource, ge.principals);
700
Enumeration<PolicyParser.PermissionEntry> enum_ =
701
ge.permissionElements();
702
while (enum_.hasMoreElements()) {
703
PolicyParser.PermissionEntry pe = enum_.nextElement();
704
705
try {
706
// perform ${{ ... }} expansions within permission name
707
expandPermissionName(pe, keyStore);
708
709
// XXX special case PrivateCredentialPermission-SELF
710
Permission perm;
711
if (pe.permission.equals
712
("javax.security.auth.PrivateCredentialPermission") &&
713
pe.name.endsWith(" self")) {
714
pe.name = pe.name.substring(0, pe.name.indexOf("self"))
715
+ SELF;
716
}
717
// check for self
718
if (pe.name != null && pe.name.indexOf(SELF) != -1) {
719
// Create a "SelfPermission" , it could be an
720
// an unresolved permission which will be resolved
721
// when implies is called
722
// Add it to entry
723
Certificate[] certs;
724
if (pe.signedBy != null) {
725
certs = getCertificates(keyStore,
726
pe.signedBy,
727
newInfo);
728
} else {
729
certs = null;
730
}
731
perm = new SelfPermission(pe.permission,
732
pe.name,
733
pe.action,
734
certs);
735
} else {
736
perm = getInstance(pe.permission,
737
pe.name,
738
pe.action);
739
}
740
entry.add(perm);
741
if (debug != null) {
742
debug.println(" "+perm);
743
}
744
} catch (ClassNotFoundException cnfe) {
745
Certificate[] certs;
746
if (pe.signedBy != null) {
747
certs = getCertificates(keyStore,
748
pe.signedBy,
749
newInfo);
750
} else {
751
certs = null;
752
}
753
754
// only add if we had no signer or we had
755
// a signer and found the keys for it.
756
if (certs != null || pe.signedBy == null) {
757
Permission perm = new UnresolvedPermission(
758
pe.permission,
759
pe.name,
760
pe.action,
761
certs);
762
entry.add(perm);
763
if (debug != null) {
764
debug.println(" "+perm);
765
}
766
}
767
} catch (java.lang.reflect.InvocationTargetException ite) {
768
Object[] source = {pe.permission,
769
ite.getCause().toString()};
770
System.err.println(
771
LocalizedMessage.getNonlocalized(
772
POLICY + ".error.adding.Permission.perm.message",
773
source));
774
} catch (Exception e) {
775
Object[] source = {pe.permission,
776
e.toString()};
777
System.err.println(
778
LocalizedMessage.getNonlocalized(
779
POLICY + ".error.adding.Permission.perm.message",
780
source));
781
}
782
}
783
784
// No need to sync because noone has access to newInfo yet
785
newInfo.policyEntries.add(entry);
786
} catch (Exception e) {
787
Object[] source = {e.toString()};
788
System.err.println(
789
LocalizedMessage.getNonlocalized(
790
POLICY + ".error.adding.Entry.message",
791
source));
792
}
793
if (debug != null)
794
debug.println();
795
}
796
797
/**
798
* Returns a new Permission object of the given Type. The Permission is
799
* created by getting the
800
* Class object using the <code>Class.forName</code> method, and using
801
* the reflection API to invoke the (String name, String actions)
802
* constructor on the
803
* object.
804
*
805
* @param type the type of Permission being created.
806
* @param name the name of the Permission being created.
807
* @param actions the actions of the Permission being created.
808
*
809
* @exception ClassNotFoundException if the particular Permission
810
* class could not be found.
811
*
812
* @exception IllegalAccessException if the class or initializer is
813
* not accessible.
814
*
815
* @exception InstantiationException if getInstance tries to
816
* instantiate an abstract class or an interface, or if the
817
* instantiation fails for some other reason.
818
*
819
* @exception NoSuchMethodException if the (String, String) constructor
820
* is not found.
821
*
822
* @exception InvocationTargetException if the underlying Permission
823
* constructor throws an exception.
824
*
825
*/
826
827
private static final Permission getInstance(String type,
828
String name,
829
String actions)
830
throws ClassNotFoundException,
831
InstantiationException,
832
IllegalAccessException,
833
NoSuchMethodException,
834
InvocationTargetException
835
{
836
Class<?> pc = Class.forName(type, false, null);
837
Permission answer = getKnownPermission(pc, name, actions);
838
if (answer != null) {
839
return answer;
840
}
841
if (!Permission.class.isAssignableFrom(pc)) {
842
// not the right subtype
843
throw new ClassCastException(type + " is not a Permission");
844
}
845
846
if (name == null && actions == null) {
847
try {
848
Constructor<?> c = pc.getConstructor(PARAMS0);
849
return (Permission) c.newInstance(new Object[] {});
850
} catch (NoSuchMethodException ne) {
851
try {
852
Constructor<?> c = pc.getConstructor(PARAMS1);
853
return (Permission) c.newInstance(
854
new Object[] { name});
855
} catch (NoSuchMethodException ne1 ) {
856
Constructor<?> c = pc.getConstructor(PARAMS2);
857
return (Permission) c.newInstance(
858
new Object[] { name, actions });
859
}
860
}
861
} else {
862
if (name != null && actions == null) {
863
try {
864
Constructor<?> c = pc.getConstructor(PARAMS1);
865
return (Permission) c.newInstance(new Object[] { name});
866
} catch (NoSuchMethodException ne) {
867
Constructor<?> c = pc.getConstructor(PARAMS2);
868
return (Permission) c.newInstance(
869
new Object[] { name, actions });
870
}
871
} else {
872
Constructor<?> c = pc.getConstructor(PARAMS2);
873
return (Permission) c.newInstance(
874
new Object[] { name, actions });
875
}
876
}
877
}
878
879
/**
880
* Creates one of the well-known permissions in the java.base module
881
* directly instead of via reflection. Keep list short to not penalize
882
* permissions from other modules.
883
*/
884
private static Permission getKnownPermission(Class<?> claz, String name,
885
String actions) {
886
if (claz.equals(FilePermission.class)) {
887
return new FilePermission(name, actions);
888
} else if (claz.equals(SocketPermission.class)) {
889
return new SocketPermission(name, actions);
890
} else if (claz.equals(RuntimePermission.class)) {
891
return new RuntimePermission(name, actions);
892
} else if (claz.equals(PropertyPermission.class)) {
893
return new PropertyPermission(name, actions);
894
} else if (claz.equals(NetPermission.class)) {
895
return new NetPermission(name, actions);
896
} else if (claz.equals(AllPermission.class)) {
897
return SecurityConstants.ALL_PERMISSION;
898
} else if (claz.equals(SecurityPermission.class)) {
899
return new SecurityPermission(name, actions);
900
} else {
901
return null;
902
}
903
}
904
905
/**
906
* Creates one of the well-known principals in the java.base module
907
* directly instead of via reflection. Keep list short to not penalize
908
* principals from other modules.
909
*/
910
private static Principal getKnownPrincipal(Class<?> claz, String name) {
911
if (claz.equals(X500Principal.class)) {
912
return new X500Principal(name);
913
} else {
914
return null;
915
}
916
}
917
918
/**
919
* Fetch all certs associated with this alias.
920
*/
921
private Certificate[] getCertificates
922
(KeyStore keyStore, String aliases, PolicyInfo newInfo) {
923
924
List<Certificate> vcerts = null;
925
926
StringTokenizer st = new StringTokenizer(aliases, ",");
927
int n = 0;
928
929
while (st.hasMoreTokens()) {
930
String alias = st.nextToken().trim();
931
n++;
932
Certificate cert = null;
933
// See if this alias's cert has already been cached
934
synchronized (newInfo.aliasMapping) {
935
cert = (Certificate)newInfo.aliasMapping.get(alias);
936
937
if (cert == null && keyStore != null) {
938
939
try {
940
cert = keyStore.getCertificate(alias);
941
} catch (KeyStoreException kse) {
942
// never happens, because keystore has already been loaded
943
// when we call this
944
}
945
if (cert != null) {
946
newInfo.aliasMapping.put(alias, cert);
947
newInfo.aliasMapping.put(cert, alias);
948
}
949
}
950
}
951
952
if (cert != null) {
953
if (vcerts == null)
954
vcerts = new ArrayList<>();
955
vcerts.add(cert);
956
}
957
}
958
959
// make sure n == vcerts.size, since we are doing a logical *and*
960
if (vcerts != null && n == vcerts.size()) {
961
Certificate[] certs = new Certificate[vcerts.size()];
962
vcerts.toArray(certs);
963
return certs;
964
} else {
965
return null;
966
}
967
}
968
969
/**
970
* Refreshes the policy object by re-reading all the policy files.
971
*/
972
@Override public void refresh() {
973
init(url);
974
}
975
976
/**
977
* Evaluates the global policy for the permissions granted to
978
* the ProtectionDomain and tests whether the permission is
979
* granted.
980
*
981
* @param pd the ProtectionDomain to test
982
* @param p the Permission object to be tested for implication.
983
*
984
* @return true if "permission" is a proper subset of a permission
985
* granted to this ProtectionDomain.
986
*
987
* @see java.security.ProtectionDomain
988
*/
989
@Override
990
public boolean implies(ProtectionDomain pd, Permission p) {
991
ProtectionDomainCache pdMap = policyInfo.getPdMapping();
992
PermissionCollection pc = pdMap.get(pd);
993
994
if (pc != null) {
995
return pc.implies(p);
996
}
997
998
pc = getPermissions(pd);
999
if (pc == null) {
1000
return false;
1001
}
1002
1003
// cache mapping of protection domain to its PermissionCollection
1004
pdMap.put(pd, pc);
1005
return pc.implies(p);
1006
}
1007
1008
/**
1009
* Examines this <code>Policy</code> and returns the permissions granted
1010
* to the specified <code>ProtectionDomain</code>. This includes
1011
* the permissions currently associated with the domain as well
1012
* as the policy permissions granted to the domain's
1013
* CodeSource, ClassLoader, and Principals.
1014
*
1015
* <p> Note that this <code>Policy</code> implementation has
1016
* special handling for PrivateCredentialPermissions.
1017
* When this method encounters a <code>PrivateCredentialPermission</code>
1018
* which specifies "self" as the <code>Principal</code> class and name,
1019
* it does not add that <code>Permission</code> to the returned
1020
* <code>PermissionCollection</code>. Instead, it builds
1021
* a new <code>PrivateCredentialPermission</code>
1022
* for each <code>Principal</code> associated with the provided
1023
* <code>Subject</code>. Each new <code>PrivateCredentialPermission</code>
1024
* contains the same Credential class as specified in the
1025
* originally granted permission, as well as the Class and name
1026
* for the respective <code>Principal</code>.
1027
*
1028
* @param domain the Permissions granted to this
1029
* <code>ProtectionDomain</code> are returned.
1030
*
1031
* @return the Permissions granted to the provided
1032
* <code>ProtectionDomain</code>.
1033
*/
1034
@Override
1035
public PermissionCollection getPermissions(ProtectionDomain domain) {
1036
Permissions perms = new Permissions();
1037
1038
if (domain == null)
1039
return perms;
1040
1041
// first get policy perms
1042
getPermissions(perms, domain);
1043
1044
// add static perms
1045
// - adding static perms after policy perms is necessary
1046
// to avoid a regression for 4301064
1047
PermissionCollection pc = domain.getPermissions();
1048
if (pc != null) {
1049
synchronized (pc) {
1050
Enumeration<Permission> e = pc.elements();
1051
while (e.hasMoreElements()) {
1052
perms.add(FilePermCompat.newPermPlusAltPath(e.nextElement()));
1053
}
1054
}
1055
}
1056
1057
return perms;
1058
}
1059
1060
/**
1061
* Examines this Policy and creates a PermissionCollection object with
1062
* the set of permissions for the specified CodeSource.
1063
*
1064
* @param codesource the CodeSource associated with the caller.
1065
* This encapsulates the original location of the code (where the code
1066
* came from) and the public key(s) of its signer.
1067
*
1068
* @return the set of permissions according to the policy.
1069
*/
1070
@Override
1071
public PermissionCollection getPermissions(CodeSource codesource) {
1072
return getPermissions(new Permissions(), codesource);
1073
}
1074
1075
/**
1076
* Examines the global policy and returns the provided Permissions
1077
* object with additional permissions granted to the specified
1078
* ProtectionDomain.
1079
*
1080
* @param perms the Permissions to populate
1081
* @param pd the ProtectionDomain associated with the caller.
1082
*
1083
* @return the set of Permissions according to the policy.
1084
*/
1085
private PermissionCollection getPermissions(Permissions perms,
1086
ProtectionDomain pd ) {
1087
if (debug != null) {
1088
debug.println("getPermissions:\n\t" + printPD(pd));
1089
}
1090
1091
final CodeSource cs = pd.getCodeSource();
1092
if (cs == null)
1093
return perms;
1094
1095
CodeSource canonCodeSource = AccessController.doPrivileged(
1096
new java.security.PrivilegedAction<>(){
1097
@Override
1098
public CodeSource run() {
1099
return canonicalizeCodebase(cs, true);
1100
}
1101
});
1102
return getPermissions(perms, canonCodeSource, pd.getPrincipals());
1103
}
1104
1105
/**
1106
* Examines the global policy and returns the provided Permissions
1107
* object with additional permissions granted to the specified
1108
* CodeSource.
1109
*
1110
* @param perms the permissions to populate
1111
* @param cs the codesource associated with the caller.
1112
* This encapsulates the original location of the code (where the code
1113
* came from) and the public key(s) of its signer.
1114
*
1115
* @return the set of permissions according to the policy.
1116
*/
1117
private PermissionCollection getPermissions(Permissions perms,
1118
final CodeSource cs) {
1119
1120
if (cs == null)
1121
return perms;
1122
1123
CodeSource canonCodeSource = AccessController.doPrivileged(
1124
new PrivilegedAction<>(){
1125
@Override
1126
public CodeSource run() {
1127
return canonicalizeCodebase(cs, true);
1128
}
1129
});
1130
1131
return getPermissions(perms, canonCodeSource, null);
1132
}
1133
1134
private Permissions getPermissions(Permissions perms,
1135
final CodeSource cs,
1136
Principal[] principals) {
1137
for (PolicyEntry entry : policyInfo.policyEntries) {
1138
addPermissions(perms, cs, principals, entry);
1139
}
1140
1141
return perms;
1142
}
1143
1144
private void addPermissions(Permissions perms,
1145
final CodeSource cs,
1146
Principal[] principals,
1147
final PolicyEntry entry) {
1148
1149
if (debug != null) {
1150
debug.println("evaluate codesources:\n" +
1151
"\tPolicy CodeSource: " + entry.getCodeSource() + "\n" +
1152
"\tActive CodeSource: " + cs);
1153
}
1154
1155
// check to see if the CodeSource implies
1156
Boolean imp = AccessController.doPrivileged
1157
(new PrivilegedAction<>() {
1158
@Override
1159
public Boolean run() {
1160
return entry.getCodeSource().implies(cs);
1161
}
1162
});
1163
if (!imp.booleanValue()) {
1164
if (debug != null) {
1165
debug.println("evaluation (codesource) failed");
1166
}
1167
1168
// CodeSource does not imply - return and try next policy entry
1169
return;
1170
}
1171
1172
// check to see if the Principals imply
1173
1174
List<PolicyParser.PrincipalEntry> entryPs = entry.getPrincipals();
1175
if (debug != null) {
1176
List<PolicyParser.PrincipalEntry> accPs = new ArrayList<>();
1177
if (principals != null) {
1178
for (int i = 0; i < principals.length; i++) {
1179
accPs.add(new PolicyParser.PrincipalEntry
1180
(principals[i].getClass().getName(),
1181
principals[i].getName()));
1182
}
1183
}
1184
debug.println("evaluate principals:\n" +
1185
"\tPolicy Principals: " + entryPs + "\n" +
1186
"\tActive Principals: " + accPs);
1187
}
1188
1189
if (entryPs == null || entryPs.isEmpty()) {
1190
1191
// policy entry has no principals -
1192
// add perms regardless of principals in current ACC
1193
1194
addPerms(perms, principals, entry);
1195
if (debug != null) {
1196
debug.println("evaluation (codesource/principals) passed");
1197
}
1198
return;
1199
1200
} else if (principals == null || principals.length == 0) {
1201
1202
// current thread has no principals but this policy entry
1203
// has principals - perms are not added
1204
1205
if (debug != null) {
1206
debug.println("evaluation (principals) failed");
1207
}
1208
return;
1209
}
1210
1211
// current thread has principals and this policy entry
1212
// has principals. see if policy entry principals match
1213
// principals in current ACC
1214
1215
for (PolicyParser.PrincipalEntry pppe : entryPs) {
1216
1217
// Check for wildcards
1218
if (pppe.isWildcardClass()) {
1219
// a wildcard class matches all principals in current ACC
1220
continue;
1221
}
1222
1223
if (pppe.isWildcardName()) {
1224
// a wildcard name matches any principal with the same class
1225
if (wildcardPrincipalNameImplies(pppe.principalClass,
1226
principals)) {
1227
continue;
1228
}
1229
if (debug != null) {
1230
debug.println("evaluation (principal name wildcard) failed");
1231
}
1232
// policy entry principal not in current ACC -
1233
// immediately return and go to next policy entry
1234
return;
1235
}
1236
1237
Set<Principal> pSet = new HashSet<>(Arrays.asList(principals));
1238
Subject subject = new Subject(true, pSet,
1239
Collections.EMPTY_SET,
1240
Collections.EMPTY_SET);
1241
try {
1242
ClassLoader cl = Thread.currentThread().getContextClassLoader();
1243
Class<?> pClass = Class.forName(pppe.principalClass, false, cl);
1244
Principal p = getKnownPrincipal(pClass, pppe.principalName);
1245
if (p == null) {
1246
if (!Principal.class.isAssignableFrom(pClass)) {
1247
// not the right subtype
1248
throw new ClassCastException(pppe.principalClass +
1249
" is not a Principal");
1250
}
1251
1252
Constructor<?> c = pClass.getConstructor(PARAMS1);
1253
p = (Principal)c.newInstance(new Object[] {
1254
pppe.principalName });
1255
1256
}
1257
1258
if (debug != null) {
1259
debug.println("found Principal " + p.getClass().getName());
1260
}
1261
1262
// check if the Principal implies the current
1263
// thread's principals
1264
if (!p.implies(subject)) {
1265
if (debug != null) {
1266
debug.println("evaluation (principal implies) failed");
1267
}
1268
1269
// policy principal does not imply the current Subject -
1270
// immediately return and go to next policy entry
1271
return;
1272
}
1273
} catch (Exception e) {
1274
// fall back to default principal comparison.
1275
// see if policy entry principal is in current ACC
1276
1277
if (debug != null) {
1278
e.printStackTrace();
1279
}
1280
1281
if (!pppe.implies(subject)) {
1282
if (debug != null) {
1283
debug.println("evaluation (default principal implies) failed");
1284
}
1285
1286
// policy entry principal not in current ACC -
1287
// immediately return and go to next policy entry
1288
return;
1289
}
1290
}
1291
1292
// either the principal information matched,
1293
// or the Principal.implies succeeded.
1294
// continue loop and test the next policy principal
1295
}
1296
1297
// all policy entry principals were found in the current ACC -
1298
// grant the policy permissions
1299
1300
if (debug != null) {
1301
debug.println("evaluation (codesource/principals) passed");
1302
}
1303
addPerms(perms, principals, entry);
1304
}
1305
1306
/**
1307
* Returns true if the array of principals contains at least one
1308
* principal of the specified class.
1309
*/
1310
private static boolean wildcardPrincipalNameImplies(String principalClass,
1311
Principal[] principals)
1312
{
1313
for (Principal p : principals) {
1314
if (principalClass.equals(p.getClass().getName())) {
1315
return true;
1316
}
1317
}
1318
return false;
1319
}
1320
1321
private void addPerms(Permissions perms,
1322
Principal[] accPs,
1323
PolicyEntry entry) {
1324
for (int i = 0; i < entry.permissions.size(); i++) {
1325
Permission p = entry.permissions.get(i);
1326
if (debug != null) {
1327
debug.println(" granting " + p);
1328
}
1329
1330
if (p instanceof SelfPermission) {
1331
// handle "SELF" permissions
1332
expandSelf((SelfPermission)p,
1333
entry.getPrincipals(),
1334
accPs,
1335
perms);
1336
} else {
1337
perms.add(FilePermCompat.newPermPlusAltPath(p));
1338
}
1339
}
1340
}
1341
1342
/**
1343
* @param sp the SelfPermission that needs to be expanded.
1344
*
1345
* @param entryPs list of principals for the Policy entry.
1346
*
1347
* @param pdp Principal array from the current ProtectionDomain.
1348
*
1349
* @param perms the PermissionCollection where the individual
1350
* Permissions will be added after expansion.
1351
*/
1352
1353
private void expandSelf(SelfPermission sp,
1354
List<PolicyParser.PrincipalEntry> entryPs,
1355
Principal[] pdp,
1356
Permissions perms) {
1357
1358
if (entryPs == null || entryPs.isEmpty()) {
1359
// No principals in the grant to substitute
1360
if (debug != null) {
1361
debug.println("Ignoring permission "
1362
+ sp.getSelfType()
1363
+ " with target name ("
1364
+ sp.getSelfName() + "). "
1365
+ "No Principal(s) specified "
1366
+ "in the grant clause. "
1367
+ "SELF-based target names are "
1368
+ "only valid in the context "
1369
+ "of a Principal-based grant entry."
1370
);
1371
}
1372
return;
1373
}
1374
int startIndex = 0;
1375
int v;
1376
StringBuilder sb = new StringBuilder();
1377
while ((v = sp.getSelfName().indexOf(SELF, startIndex)) != -1) {
1378
1379
// add non-SELF string
1380
sb.append(sp.getSelfName().substring(startIndex, v));
1381
1382
// expand SELF
1383
Iterator<PolicyParser.PrincipalEntry> pli = entryPs.iterator();
1384
while (pli.hasNext()) {
1385
PolicyParser.PrincipalEntry pppe = pli.next();
1386
String[][] principalInfo = getPrincipalInfo(pppe,pdp);
1387
for (int i = 0; i < principalInfo.length; i++) {
1388
if (i != 0) {
1389
sb.append(", ");
1390
}
1391
sb.append(principalInfo[i][0] + " " +
1392
"\"" + principalInfo[i][1] + "\"");
1393
}
1394
if (pli.hasNext()) {
1395
sb.append(", ");
1396
}
1397
}
1398
startIndex = v + SELF.length();
1399
}
1400
// add remaining string (might be the entire string)
1401
sb.append(sp.getSelfName().substring(startIndex));
1402
1403
if (debug != null) {
1404
debug.println(" expanded:\n\t" + sp.getSelfName()
1405
+ "\n into:\n\t" + sb.toString());
1406
}
1407
try {
1408
// first try to instantiate the permission
1409
perms.add(FilePermCompat.newPermPlusAltPath(getInstance(sp.getSelfType(),
1410
sb.toString(),
1411
sp.getSelfActions())));
1412
} catch (ClassNotFoundException cnfe) {
1413
// ok, the permission is not in the bootclasspath.
1414
// before we add an UnresolvedPermission, check to see
1415
// whether this perm already belongs to the collection.
1416
// if so, use that perm's ClassLoader to create a new
1417
// one.
1418
Class<?> pc = null;
1419
synchronized (perms) {
1420
Enumeration<Permission> e = perms.elements();
1421
while (e.hasMoreElements()) {
1422
Permission pElement = e.nextElement();
1423
if (pElement.getClass().getName().equals(sp.getSelfType())) {
1424
pc = pElement.getClass();
1425
break;
1426
}
1427
}
1428
}
1429
if (pc == null) {
1430
// create an UnresolvedPermission
1431
perms.add(new UnresolvedPermission(sp.getSelfType(),
1432
sb.toString(),
1433
sp.getSelfActions(),
1434
sp.getCerts()));
1435
} else {
1436
try {
1437
// we found an instantiated permission.
1438
// use its class loader to instantiate a new permission.
1439
Constructor<?> c;
1440
// name parameter can not be null
1441
if (sp.getSelfActions() == null) {
1442
try {
1443
c = pc.getConstructor(PARAMS1);
1444
perms.add((Permission)c.newInstance
1445
(new Object[] {sb.toString()}));
1446
} catch (NoSuchMethodException ne) {
1447
c = pc.getConstructor(PARAMS2);
1448
perms.add((Permission)c.newInstance
1449
(new Object[] {sb.toString(),
1450
sp.getSelfActions() }));
1451
}
1452
} else {
1453
c = pc.getConstructor(PARAMS2);
1454
perms.add((Permission)c.newInstance
1455
(new Object[] {sb.toString(),
1456
sp.getSelfActions()}));
1457
}
1458
} catch (Exception nme) {
1459
if (debug != null) {
1460
debug.println("self entry expansion " +
1461
" instantiation failed: "
1462
+ nme.toString());
1463
}
1464
}
1465
}
1466
} catch (Exception e) {
1467
if (debug != null) {
1468
debug.println(e.toString());
1469
}
1470
}
1471
}
1472
1473
/**
1474
* return the principal class/name pair in the 2D array.
1475
* array[x][y]: x corresponds to the array length.
1476
* if (y == 0), it's the principal class.
1477
* if (y == 1), it's the principal name.
1478
*/
1479
private String[][] getPrincipalInfo
1480
(PolicyParser.PrincipalEntry pe, Principal[] pdp) {
1481
1482
// there are 3 possibilities:
1483
// 1) the entry's Principal class and name are not wildcarded
1484
// 2) the entry's Principal name is wildcarded only
1485
// 3) the entry's Principal class and name are wildcarded
1486
1487
if (!pe.isWildcardClass() && !pe.isWildcardName()) {
1488
1489
// build an info array for the principal
1490
// from the Policy entry
1491
String[][] info = new String[1][2];
1492
info[0][0] = pe.principalClass;
1493
info[0][1] = pe.principalName;
1494
return info;
1495
1496
} else if (!pe.isWildcardClass() && pe.isWildcardName()) {
1497
1498
// build an info array for every principal
1499
// in the current domain which has a principal class
1500
// that is equal to policy entry principal class name
1501
List<Principal> plist = new ArrayList<>();
1502
for (int i = 0; i < pdp.length; i++) {
1503
if (pe.principalClass.equals(pdp[i].getClass().getName()))
1504
plist.add(pdp[i]);
1505
}
1506
String[][] info = new String[plist.size()][2];
1507
int i = 0;
1508
for (Principal p : plist) {
1509
info[i][0] = p.getClass().getName();
1510
info[i][1] = p.getName();
1511
i++;
1512
}
1513
return info;
1514
1515
} else {
1516
1517
// build an info array for every
1518
// one of the current Domain's principals
1519
1520
String[][] info = new String[pdp.length][2];
1521
1522
for (int i = 0; i < pdp.length; i++) {
1523
info[i][0] = pdp[i].getClass().getName();
1524
info[i][1] = pdp[i].getName();
1525
}
1526
return info;
1527
}
1528
}
1529
1530
/*
1531
* Returns the signer certificates from the list of certificates
1532
* associated with the given code source.
1533
*
1534
* The signer certificates are those certificates that were used
1535
* to verify signed code originating from the codesource location.
1536
*
1537
* This method assumes that in the given code source, each signer
1538
* certificate is followed by its supporting certificate chain
1539
* (which may be empty), and that the signer certificate and its
1540
* supporting certificate chain are ordered bottom-to-top
1541
* (i.e., with the signer certificate first and the (root) certificate
1542
* authority last).
1543
*/
1544
protected Certificate[] getSignerCertificates(CodeSource cs) {
1545
Certificate[] certs = null;
1546
if ((certs = cs.getCertificates()) == null)
1547
return null;
1548
for (int i=0; i<certs.length; i++) {
1549
if (!(certs[i] instanceof X509Certificate))
1550
return cs.getCertificates();
1551
}
1552
1553
// Do we have to do anything?
1554
int i = 0;
1555
int count = 0;
1556
while (i < certs.length) {
1557
count++;
1558
while (((i+1) < certs.length)
1559
&& ((X509Certificate)certs[i]).getIssuerX500Principal().equals(
1560
((X509Certificate)certs[i+1]).getSubjectX500Principal())) {
1561
i++;
1562
}
1563
i++;
1564
}
1565
if (count == certs.length)
1566
// Done
1567
return certs;
1568
1569
List<Certificate> userCertList = new ArrayList<>();
1570
i = 0;
1571
while (i < certs.length) {
1572
userCertList.add(certs[i]);
1573
while (((i+1) < certs.length)
1574
&& ((X509Certificate)certs[i]).getIssuerX500Principal().equals(
1575
((X509Certificate)certs[i+1]).getSubjectX500Principal())) {
1576
i++;
1577
}
1578
i++;
1579
}
1580
Certificate[] userCerts = new Certificate[userCertList.size()];
1581
userCertList.toArray(userCerts);
1582
return userCerts;
1583
}
1584
1585
private CodeSource canonicalizeCodebase(CodeSource cs,
1586
boolean extractSignerCerts) {
1587
1588
String path = null;
1589
1590
CodeSource canonCs = cs;
1591
URL u = cs.getLocation();
1592
if (u != null) {
1593
if (u.getProtocol().equals("jar")) {
1594
// unwrap url embedded inside jar url
1595
String spec = u.getFile();
1596
int separator = spec.indexOf("!/");
1597
if (separator != -1) {
1598
try {
1599
u = new URL(spec.substring(0, separator));
1600
} catch (MalformedURLException e) {
1601
// Fail silently. In this case, url stays what
1602
// it was above
1603
}
1604
}
1605
}
1606
if (u.getProtocol().equals("file")) {
1607
boolean isLocalFile = false;
1608
String host = u.getHost();
1609
isLocalFile = (host == null || host.isEmpty() ||
1610
host.equals("~") || host.equalsIgnoreCase("localhost"));
1611
1612
if (isLocalFile) {
1613
path = u.getFile().replace('/', File.separatorChar);
1614
path = ParseUtil.decode(path);
1615
}
1616
}
1617
}
1618
1619
if (path != null) {
1620
try {
1621
URL csUrl = null;
1622
path = canonPath(path);
1623
csUrl = ParseUtil.fileToEncodedURL(new File(path));
1624
1625
if (extractSignerCerts) {
1626
canonCs = new CodeSource(csUrl,
1627
getSignerCertificates(cs));
1628
} else {
1629
canonCs = new CodeSource(csUrl,
1630
cs.getCertificates());
1631
}
1632
} catch (IOException ioe) {
1633
// leave codesource as it is, unless we have to extract its
1634
// signer certificates
1635
if (extractSignerCerts) {
1636
canonCs = new CodeSource(cs.getLocation(),
1637
getSignerCertificates(cs));
1638
}
1639
}
1640
} else {
1641
if (extractSignerCerts) {
1642
canonCs = new CodeSource(cs.getLocation(),
1643
getSignerCertificates(cs));
1644
}
1645
}
1646
return canonCs;
1647
}
1648
1649
// Wrapper to return a canonical path that avoids calling getCanonicalPath()
1650
// with paths that are intended to match all entries in the directory
1651
private static String canonPath(String path) throws IOException {
1652
if (path.endsWith("*")) {
1653
path = path.substring(0, path.length()-1) + "-";
1654
path = new File(path).getCanonicalPath();
1655
return path.substring(0, path.length()-1) + "*";
1656
} else {
1657
return new File(path).getCanonicalPath();
1658
}
1659
}
1660
1661
private String printPD(ProtectionDomain pd) {
1662
Principal[] principals = pd.getPrincipals();
1663
String pals = "<no principals>";
1664
if (principals != null && principals.length > 0) {
1665
StringBuilder palBuf = new StringBuilder("(principals ");
1666
for (int i = 0; i < principals.length; i++) {
1667
palBuf.append(principals[i].getClass().getName() +
1668
" \"" + principals[i].getName() +
1669
"\"");
1670
if (i < principals.length-1)
1671
palBuf.append(", ");
1672
else
1673
palBuf.append(")");
1674
}
1675
pals = palBuf.toString();
1676
}
1677
return "PD CodeSource: "
1678
+ pd.getCodeSource()
1679
+"\n\t" + "PD ClassLoader: "
1680
+ pd.getClassLoader()
1681
+"\n\t" + "PD Principals: "
1682
+ pals;
1683
}
1684
1685
/**
1686
* return true if no replacement was performed,
1687
* or if replacement succeeded.
1688
*/
1689
private boolean replacePrincipals(
1690
List<PolicyParser.PrincipalEntry> principals, KeyStore keystore) {
1691
1692
if (principals == null || principals.isEmpty() || keystore == null)
1693
return true;
1694
1695
for (PolicyParser.PrincipalEntry pppe : principals) {
1696
if (pppe.isReplaceName()) {
1697
1698
// perform replacement
1699
// (only X509 replacement is possible now)
1700
String name;
1701
if ((name = getDN(pppe.principalName, keystore)) == null) {
1702
return false;
1703
}
1704
1705
if (debug != null) {
1706
debug.println(" Replacing \"" +
1707
pppe.principalName +
1708
"\" with " +
1709
X500PRINCIPAL + "/\"" +
1710
name +
1711
"\"");
1712
}
1713
1714
pppe.principalClass = X500PRINCIPAL;
1715
pppe.principalName = name;
1716
}
1717
}
1718
// return true if no replacement was performed,
1719
// or if replacement succeeded
1720
return true;
1721
}
1722
1723
private void expandPermissionName(PolicyParser.PermissionEntry pe,
1724
KeyStore keystore) throws Exception {
1725
// short cut the common case
1726
if (pe.name == null || pe.name.indexOf("${{", 0) == -1) {
1727
return;
1728
}
1729
1730
int startIndex = 0;
1731
int b, e;
1732
StringBuilder sb = new StringBuilder();
1733
while ((b = pe.name.indexOf("${{", startIndex)) != -1) {
1734
e = pe.name.indexOf("}}", b);
1735
if (e < 1) {
1736
break;
1737
}
1738
sb.append(pe.name.substring(startIndex, b));
1739
1740
// get the value in ${{...}}
1741
String value = pe.name.substring(b+3, e);
1742
1743
// parse up to the first ':'
1744
int colonIndex;
1745
String prefix = value;
1746
String suffix;
1747
if ((colonIndex = value.indexOf(':')) != -1) {
1748
prefix = value.substring(0, colonIndex);
1749
}
1750
1751
// handle different prefix possibilities
1752
if (prefix.equalsIgnoreCase("self")) {
1753
// do nothing - handled later
1754
sb.append(pe.name.substring(b, e+2));
1755
startIndex = e+2;
1756
continue;
1757
} else if (prefix.equalsIgnoreCase("alias")) {
1758
// get the suffix and perform keystore alias replacement
1759
if (colonIndex == -1) {
1760
Object[] source = {pe.name};
1761
throw new Exception(
1762
LocalizedMessage.getNonlocalized(
1763
"alias.name.not.provided.pe.name.",
1764
source));
1765
}
1766
suffix = value.substring(colonIndex+1);
1767
if ((suffix = getDN(suffix, keystore)) == null) {
1768
Object[] source = {value.substring(colonIndex+1)};
1769
throw new Exception(
1770
LocalizedMessage.getNonlocalized(
1771
"unable.to.perform.substitution.on.alias.suffix",
1772
source));
1773
}
1774
1775
sb.append(X500PRINCIPAL + " \"" + suffix + "\"");
1776
startIndex = e+2;
1777
} else {
1778
Object[] source = {prefix};
1779
throw new Exception(
1780
LocalizedMessage.getNonlocalized(
1781
"substitution.value.prefix.unsupported",
1782
source));
1783
}
1784
}
1785
1786
// copy the rest of the value
1787
sb.append(pe.name.substring(startIndex));
1788
1789
// replace the name with expanded value
1790
if (debug != null) {
1791
debug.println(" Permission name expanded from:\n\t" +
1792
pe.name + "\nto\n\t" + sb.toString());
1793
}
1794
pe.name = sb.toString();
1795
}
1796
1797
private String getDN(String alias, KeyStore keystore) {
1798
Certificate cert = null;
1799
try {
1800
cert = keystore.getCertificate(alias);
1801
} catch (Exception e) {
1802
if (debug != null) {
1803
debug.println(" Error retrieving certificate for '" +
1804
alias +
1805
"': " +
1806
e.toString());
1807
}
1808
return null;
1809
}
1810
1811
if (cert == null || !(cert instanceof X509Certificate)) {
1812
if (debug != null) {
1813
debug.println(" -- No certificate for '" +
1814
alias +
1815
"' - ignoring entry");
1816
}
1817
return null;
1818
} else {
1819
X509Certificate x509Cert = (X509Certificate)cert;
1820
1821
// 4702543: X500 names with an EmailAddress
1822
// were encoded incorrectly. create new
1823
// X500Principal name with correct encoding
1824
1825
X500Principal p = new X500Principal
1826
(x509Cert.getSubjectX500Principal().toString());
1827
return p.getName();
1828
}
1829
}
1830
1831
/**
1832
* Each entry in the policy configuration file is represented by a
1833
* PolicyEntry object. <p>
1834
*
1835
* A PolicyEntry is a (CodeSource,Permission) pair. The
1836
* CodeSource contains the (URL, PublicKey) that together identify
1837
* where the Java bytecodes come from and who (if anyone) signed
1838
* them. The URL could refer to localhost. The URL could also be
1839
* null, meaning that this policy entry is given to all comers, as
1840
* long as they match the signer field. The signer could be null,
1841
* meaning the code is not signed. <p>
1842
*
1843
* The Permission contains the (Type, Name, Action) triplet. <p>
1844
*
1845
* For now, the Policy object retrieves the public key from the
1846
* X.509 certificate on disk that corresponds to the signedBy
1847
* alias specified in the Policy config file. For reasons of
1848
* efficiency, the Policy object keeps a hashtable of certs already
1849
* read in. This could be replaced by a secure internal key
1850
* store.
1851
*
1852
* <p>
1853
* For example, the entry
1854
* <pre>
1855
* permission java.io.File "/tmp", "read,write",
1856
* signedBy "Duke";
1857
* </pre>
1858
* is represented internally
1859
* <pre>
1860
*
1861
* FilePermission f = new FilePermission("/tmp", "read,write");
1862
* PublicKey p = publickeys.get("Duke");
1863
* URL u = InetAddress.getLocalHost();
1864
* CodeBase c = new CodeBase( p, u );
1865
* pe = new PolicyEntry(f, c);
1866
* </pre>
1867
*
1868
* @author Marianne Mueller
1869
* @author Roland Schemers
1870
* @see java.security.CodeSource
1871
* @see java.security.Policy
1872
* @see java.security.Permissions
1873
* @see java.security.ProtectionDomain
1874
*/
1875
private static class PolicyEntry {
1876
1877
private final CodeSource codesource;
1878
final List<Permission> permissions;
1879
private final List<PolicyParser.PrincipalEntry> principals;
1880
1881
/**
1882
* Given a Permission and a CodeSource, create a policy entry.
1883
*
1884
* XXX Decide if/how to add validity fields and "purpose" fields to
1885
* XXX policy entries
1886
*
1887
* @param cs the CodeSource, which encapsulates the URL and the
1888
* public key
1889
* attributes from the policy config file. Validity checks
1890
* are performed on the public key before PolicyEntry is
1891
* called.
1892
*
1893
*/
1894
PolicyEntry(CodeSource cs, List<PolicyParser.PrincipalEntry> principals)
1895
{
1896
this.codesource = cs;
1897
this.permissions = new ArrayList<Permission>();
1898
this.principals = principals; // can be null
1899
}
1900
1901
PolicyEntry(CodeSource cs)
1902
{
1903
this(cs, null);
1904
}
1905
1906
List<PolicyParser.PrincipalEntry> getPrincipals() {
1907
return principals; // can be null
1908
}
1909
1910
/**
1911
* add a Permission object to this entry.
1912
* No need to sync add op because perms are added to entry only
1913
* while entry is being initialized
1914
*/
1915
void add(Permission p) {
1916
permissions.add(p);
1917
}
1918
1919
/**
1920
* Return the CodeSource for this policy entry
1921
*/
1922
CodeSource getCodeSource() {
1923
return codesource;
1924
}
1925
1926
@Override public String toString(){
1927
StringBuilder sb = new StringBuilder();
1928
sb.append(ResourcesMgr.getString("LPARAM"));
1929
sb.append(getCodeSource());
1930
sb.append("\n");
1931
for (int j = 0; j < permissions.size(); j++) {
1932
Permission p = permissions.get(j);
1933
sb.append(ResourcesMgr.getString("SPACE"));
1934
sb.append(ResourcesMgr.getString("SPACE"));
1935
sb.append(p);
1936
sb.append(ResourcesMgr.getString("NEWLINE"));
1937
}
1938
sb.append(ResourcesMgr.getString("RPARAM"));
1939
sb.append(ResourcesMgr.getString("NEWLINE"));
1940
return sb.toString();
1941
}
1942
}
1943
1944
private static class SelfPermission extends Permission {
1945
1946
@java.io.Serial
1947
private static final long serialVersionUID = -8315562579967246806L;
1948
1949
/**
1950
* The class name of the Permission class that will be
1951
* created when this self permission is expanded .
1952
*
1953
* @serial
1954
*/
1955
private String type;
1956
1957
/**
1958
* The permission name.
1959
*
1960
* @serial
1961
*/
1962
private String name;
1963
1964
/**
1965
* The actions of the permission.
1966
*
1967
* @serial
1968
*/
1969
private String actions;
1970
1971
/**
1972
* The certs of the permission.
1973
*
1974
* @serial
1975
*/
1976
private Certificate[] certs;
1977
1978
/**
1979
* Creates a new SelfPermission containing the permission
1980
* information needed later to expand the self
1981
* @param type the class name of the Permission class that will be
1982
* created when this permission is expanded and if necessary resolved.
1983
* @param name the name of the permission.
1984
* @param actions the actions of the permission.
1985
* @param certs the certificates the permission's class was signed with.
1986
* This is a list of certificate chains, where each chain is composed of
1987
* a signer certificate and optionally its supporting certificate chain.
1988
* Each chain is ordered bottom-to-top (i.e., with the signer
1989
* certificate first and the (root) certificate authority last).
1990
*/
1991
public SelfPermission(String type, String name, String actions,
1992
Certificate[] certs)
1993
{
1994
super(type);
1995
if (type == null) {
1996
throw new NullPointerException
1997
(LocalizedMessage.getNonlocalized("type.can.t.be.null"));
1998
}
1999
this.type = type;
2000
this.name = name;
2001
this.actions = actions;
2002
if (certs != null) {
2003
// Extract the signer certs from the list of certificates.
2004
for (int i=0; i<certs.length; i++) {
2005
if (!(certs[i] instanceof X509Certificate)) {
2006
// there is no concept of signer certs, so we store the
2007
// entire cert array
2008
this.certs = certs.clone();
2009
break;
2010
}
2011
}
2012
2013
if (this.certs == null) {
2014
// Go through the list of certs and see if all the certs are
2015
// signer certs.
2016
int i = 0;
2017
int count = 0;
2018
while (i < certs.length) {
2019
count++;
2020
while (((i+1) < certs.length) &&
2021
((X509Certificate)certs[i]).getIssuerX500Principal().equals(
2022
((X509Certificate)certs[i+1]).getSubjectX500Principal())) {
2023
i++;
2024
}
2025
i++;
2026
}
2027
if (count == certs.length) {
2028
// All the certs are signer certs, so we store the
2029
// entire array
2030
this.certs = certs.clone();
2031
}
2032
2033
if (this.certs == null) {
2034
// extract the signer certs
2035
List<Certificate> signerCerts = new ArrayList<>();
2036
i = 0;
2037
while (i < certs.length) {
2038
signerCerts.add(certs[i]);
2039
while (((i+1) < certs.length) &&
2040
((X509Certificate)certs[i]).getIssuerX500Principal().equals(
2041
((X509Certificate)certs[i+1]).getSubjectX500Principal())) {
2042
i++;
2043
}
2044
i++;
2045
}
2046
this.certs = new Certificate[signerCerts.size()];
2047
signerCerts.toArray(this.certs);
2048
}
2049
}
2050
}
2051
}
2052
2053
/**
2054
* This method always returns false for SelfPermission permissions.
2055
* That is, an SelfPermission never considered to
2056
* imply another permission.
2057
*
2058
* @param p the permission to check against.
2059
*
2060
* @return false.
2061
*/
2062
@Override public boolean implies(Permission p) {
2063
return false;
2064
}
2065
2066
/**
2067
* Checks two SelfPermission objects for equality.
2068
*
2069
* Checks that <i>obj</i> is an SelfPermission, and has
2070
* the same type (class) name, permission name, actions, and
2071
* certificates as this object.
2072
*
2073
* @param obj the object we are testing for equality with this object.
2074
*
2075
* @return true if obj is an SelfPermission, and has the same
2076
* type (class) name, permission name, actions, and
2077
* certificates as this object.
2078
*/
2079
@Override public boolean equals(Object obj) {
2080
if (obj == this)
2081
return true;
2082
2083
if (! (obj instanceof SelfPermission))
2084
return false;
2085
SelfPermission that = (SelfPermission) obj;
2086
2087
if (!(this.type.equals(that.type) &&
2088
this.name.equals(that.name) &&
2089
this.actions.equals(that.actions)))
2090
return false;
2091
2092
if (this.certs.length != that.certs.length)
2093
return false;
2094
2095
int i,j;
2096
boolean match;
2097
2098
for (i = 0; i < this.certs.length; i++) {
2099
match = false;
2100
for (j = 0; j < that.certs.length; j++) {
2101
if (this.certs[i].equals(that.certs[j])) {
2102
match = true;
2103
break;
2104
}
2105
}
2106
if (!match) return false;
2107
}
2108
2109
for (i = 0; i < that.certs.length; i++) {
2110
match = false;
2111
for (j = 0; j < this.certs.length; j++) {
2112
if (that.certs[i].equals(this.certs[j])) {
2113
match = true;
2114
break;
2115
}
2116
}
2117
if (!match) return false;
2118
}
2119
return true;
2120
}
2121
2122
/**
2123
* Returns the hash code value for this object.
2124
*
2125
* @return a hash code value for this object.
2126
*/
2127
@Override public int hashCode() {
2128
int hash = type.hashCode();
2129
if (name != null)
2130
hash ^= name.hashCode();
2131
if (actions != null)
2132
hash ^= actions.hashCode();
2133
return hash;
2134
}
2135
2136
/**
2137
* Returns the canonical string representation of the actions,
2138
* which currently is the empty string "", since there are no actions
2139
* for an SelfPermission. That is, the actions for the
2140
* permission that will be created when this SelfPermission
2141
* is resolved may be non-null, but an SelfPermission
2142
* itself is never considered to have any actions.
2143
*
2144
* @return the empty string "".
2145
*/
2146
@Override public String getActions() {
2147
return "";
2148
}
2149
2150
public String getSelfType() {
2151
return type;
2152
}
2153
2154
public String getSelfName() {
2155
return name;
2156
}
2157
2158
public String getSelfActions() {
2159
return actions;
2160
}
2161
2162
public Certificate[] getCerts() {
2163
return certs;
2164
}
2165
2166
/**
2167
* Returns a string describing this SelfPermission. The convention
2168
* is to specify the class name, the permission name, and the actions,
2169
* in the following format: '(unresolved "ClassName" "name" "actions")'.
2170
*
2171
* @return information about this SelfPermission.
2172
*/
2173
@Override public String toString() {
2174
return "(SelfPermission " + type + " " + name + " " + actions + ")";
2175
}
2176
}
2177
2178
/**
2179
* holds policy information that we need to synch on
2180
*/
2181
private static class PolicyInfo {
2182
private static final boolean verbose = false;
2183
2184
// Stores grant entries in the policy
2185
final List<PolicyEntry> policyEntries;
2186
2187
// Maps aliases to certs
2188
final Map<Object, Object> aliasMapping;
2189
2190
// Maps ProtectionDomain to PermissionCollection
2191
private final ProtectionDomainCache[] pdMapping;
2192
private java.util.Random random;
2193
2194
PolicyInfo(int numCaches) {
2195
policyEntries = new ArrayList<>();
2196
aliasMapping = Collections.synchronizedMap(new HashMap<>(11));
2197
2198
pdMapping = new ProtectionDomainCache[numCaches];
2199
JavaSecurityAccess jspda
2200
= SharedSecrets.getJavaSecurityAccess();
2201
for (int i = 0; i < numCaches; i++) {
2202
pdMapping[i] = jspda.getProtectionDomainCache();
2203
}
2204
if (numCaches > 1) {
2205
random = new java.util.Random();
2206
}
2207
}
2208
ProtectionDomainCache getPdMapping() {
2209
if (pdMapping.length == 1) {
2210
return pdMapping[0];
2211
} else {
2212
int i = java.lang.Math.abs(random.nextInt() % pdMapping.length);
2213
return pdMapping[i];
2214
}
2215
}
2216
}
2217
}
2218
2219