1 /*
2 * Copyright (c) 1997, 2018, 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.Path;
34 import java.util.*;
35 import java.security.*;
36 import java.security.cert.Certificate;
37 import java.security.cert.X509Certificate;
38 import javax.security.auth.Subject;
39 import javax.security.auth.x500.X500Principal;
40 import java.io.FilePermission;
41 import java.net.SocketPermission;
42 import java.net.NetPermission;
43 import java.util.concurrent.ConcurrentHashMap;
44 import jdk.internal.access.JavaSecurityAccess;
45 import static jdk.internal.access.JavaSecurityAccess.ProtectionDomainCache;
46 import jdk.internal.access.SharedSecrets;
47 import jdk.internal.util.StaticProperty;
48 import sun.security.util.*;
49 import sun.net.www.ParseUtil;
50
51 /**
52 * This class represents a default Policy implementation for the
53 * "JavaPolicy" type.
54 *
55 * <p> This object stores the policy for the entire Java runtime,
56 * and is the amalgamation of multiple static policy
57 * configurations that resides in files.
58 * The algorithm for locating the policy file(s) and reading their
59 * information into this <code>Policy</code> object is:
60 *
256 private boolean allowSystemProperties = true;
257 private boolean notUtf8 = false;
258 private URL url;
259
260 // for use with the reflection API
261 private static final Class<?>[] PARAMS0 = { };
262 private static final Class<?>[] PARAMS1 = { String.class };
263 private static final Class<?>[] PARAMS2 = { String.class, String.class };
264
265 /**
266 * When a policy file has a syntax error, the exception code may generate
267 * another permission check and this can cause the policy file to be parsed
268 * repeatedly, leading to a StackOverflowError or ClassCircularityError.
269 * To avoid this, this set is populated with policy files that have been
270 * previously parsed and have syntax errors, so that they can be
271 * subsequently ignored.
272 */
273 private static Set<URL> badPolicyURLs =
274 Collections.newSetFromMap(new ConcurrentHashMap<URL,Boolean>());
275
276 // The default.policy file
277 private static final URL DEFAULT_POLICY_URL =
278 AccessController.doPrivileged(new PrivilegedAction<>() {
279 @Override
280 public URL run() {
281 String sep = File.separator;
282 try {
283 return Path.of(StaticProperty.javaHome(),
284 "lib", "security",
285 "default.policy").toUri().toURL();
286 } catch (MalformedURLException mue) {
287 // should not happen
288 throw new Error("Malformed default.policy URL: " + mue);
289 }
290 }
291 });
292
293 /**
294 * Initializes the Policy object and reads the default policy
295 * configuration file(s) into the Policy object.
296 */
297 public PolicyFile() {
298 init((URL)null);
299 }
300
301 /**
302 * Initializes the Policy object and reads the default policy
303 * from the specified URL only.
304 */
305 public PolicyFile(URL url) {
306 this.url = url;
307 init(url);
308 }
309
310 /**
311 * Initializes the Policy object and reads the default policy
312 * configuration file(s) into the Policy object.
332
333 int numCaches;
334 if (numCacheStr != null) {
335 try {
336 numCaches = Integer.parseInt(numCacheStr);
337 } catch (NumberFormatException e) {
338 numCaches = DEFAULT_CACHE_SIZE;
339 }
340 } else {
341 numCaches = DEFAULT_CACHE_SIZE;
342 }
343 // System.out.println("number caches=" + numCaches);
344 PolicyInfo newInfo = new PolicyInfo(numCaches);
345 initPolicyFile(newInfo, url);
346 policyInfo = newInfo;
347 }
348
349 private void initPolicyFile(final PolicyInfo newInfo, final URL url) {
350
351 // always load default.policy
352 if (debug != null) {
353 debug.println("reading " + DEFAULT_POLICY_URL);
354 }
355 AccessController.doPrivileged(new PrivilegedAction<>() {
356 @Override
357 public Void run() {
358 init(DEFAULT_POLICY_URL, newInfo, true);
359 return null;
360 }
361 });
362
363 if (url != null) {
364
365 /**
366 * If the caller specified a URL via Policy.getInstance,
367 * we only read from default.policy and that URL.
368 */
369
370 if (debug != null) {
371 debug.println("reading " + url);
372 }
373 AccessController.doPrivileged(new PrivilegedAction<>() {
374 @Override
375 public Void run() {
376 if (init(url, newInfo, false) == false) {
377 // use static policy if all else fails
378 initStaticPolicy(newInfo);
379 }
380 return null;
381 }
382 });
383
384 } else {
385
386 /**
387 * Caller did not specify URL via Policy.getInstance.
388 * Read from URLs listed in the java.security properties file.
389 */
390
391 boolean loaded_one = initPolicyFile(POLICY, POLICY_URL, newInfo);
392 // To maintain strict backward compatibility
393 // we load the static policy only if POLICY load failed
394 if (!loaded_one) {
395 // use static policy if all else fails
396 initStaticPolicy(newInfo);
412 boolean overrideAll = false;
413 if (extra_policy.startsWith("=")) {
414 overrideAll = true;
415 extra_policy = extra_policy.substring(1);
416 }
417 try {
418 extra_policy =
419 PropertyExpander.expand(extra_policy);
420 URL policyURL;
421
422 File policyFile = new File(extra_policy);
423 if (policyFile.exists()) {
424 policyURL = ParseUtil.fileToEncodedURL
425 (new File(policyFile.getCanonicalPath()));
426 } else {
427 policyURL = new URL(extra_policy);
428 }
429 if (debug != null) {
430 debug.println("reading "+policyURL);
431 }
432 if (init(policyURL, newInfo, false)) {
433 loaded_policy = true;
434 }
435 } catch (Exception e) {
436 // ignore.
437 if (debug != null) {
438 debug.println("caught exception: "+e);
439 }
440 }
441 if (overrideAll) {
442 if (debug != null) {
443 debug.println("overriding other policies!");
444 }
445 return Boolean.valueOf(loaded_policy);
446 }
447 }
448 }
449
450 int n = 1;
451 String policy_uri;
452
455 URL policy_url = null;
456 String expanded_uri = PropertyExpander.expand
457 (policy_uri).replace(File.separatorChar, '/');
458
459 if (policy_uri.startsWith("file:${java.home}/") ||
460 policy_uri.startsWith("file:${user.home}/")) {
461
462 // this special case accommodates
463 // the situation java.home/user.home
464 // expand to a single slash, resulting in
465 // a file://foo URI
466 policy_url = new File
467 (expanded_uri.substring(5)).toURI().toURL();
468 } else {
469 policy_url = new URI(expanded_uri).toURL();
470 }
471
472 if (debug != null) {
473 debug.println("reading " + policy_url);
474 }
475 if (init(policy_url, newInfo, false)) {
476 loaded_policy = true;
477 }
478 } catch (Exception e) {
479 if (debug != null) {
480 debug.println(
481 "Debug info only. Error reading policy " +e);
482 e.printStackTrace();
483 }
484 // ignore that policy
485 }
486 n++;
487 }
488 return Boolean.valueOf(loaded_policy);
489 }
490 });
491
492 return loadedPolicy;
493 }
494
495 /**
496 * Reads a policy configuration into the Policy object using a
497 * Reader object.
498 */
499 private boolean init(URL policy, PolicyInfo newInfo, boolean defPolicy) {
500
501 // skip parsing policy file if it has been previously parsed and
502 // has syntax errors
503 if (badPolicyURLs.contains(policy)) {
504 if (debug != null) {
505 debug.println("skipping bad policy file: " + policy);
506 }
507 return false;
508 }
509
510 try (InputStreamReader isr =
511 getInputStreamReader(PolicyUtil.getInputStream(policy))) {
512
513 PolicyParser pp = new PolicyParser(expandProperties);
514 pp.read(isr);
515
516 KeyStore keyStore = null;
517 try {
518 keyStore = PolicyUtil.getKeyStore
519 (policy,
520 pp.getKeyStoreUrl(),
521 pp.getKeyStoreType(),
522 pp.getKeyStoreProvider(),
523 pp.getStorePassURL(),
524 debug);
525 } catch (Exception e) {
526 // ignore, treat it like we have no keystore
527 if (debug != null) {
528 debug.println("Debug info only. Ignoring exception.");
529 e.printStackTrace();
530 }
531 }
532
533 Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
534 while (enum_.hasMoreElements()) {
535 PolicyParser.GrantEntry ge = enum_.nextElement();
536 addGrantEntry(ge, keyStore, newInfo);
537 }
538 return true;
539 } catch (PolicyParser.ParsingException pe) {
540 if (defPolicy) {
541 throw new InternalError("Failed to load default.policy", pe);
542 }
543 // record bad policy file to avoid later reparsing it
544 badPolicyURLs.add(policy);
545 Object[] source = {policy, pe.getNonlocalizedMessage()};
546 System.err.println(LocalizedMessage.getNonlocalized
547 (POLICY + ".error.parsing.policy.message", source));
548 if (debug != null) {
549 pe.printStackTrace();
550 }
551 } catch (Exception e) {
552 if (defPolicy) {
553 throw new InternalError("Failed to load default.policy", e);
554 }
555 if (debug != null) {
556 debug.println("error parsing "+policy);
557 debug.println(e.toString());
558 e.printStackTrace();
559 }
560 }
561
562 return false;
563 }
564
565 private InputStreamReader getInputStreamReader(InputStream is)
566 throws IOException {
567 /*
568 * Read in policy using UTF-8 by default.
569 *
570 * Check non-standard system property to see if the default encoding
571 * should be used instead.
572 */
573 return (notUtf8)
574 ? new InputStreamReader(is)
|
1 /*
2 * Copyright (c) 1997, 2019, 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 static jdk.internal.access.JavaSecurityAccess.ProtectionDomainCache;
46 import jdk.internal.access.SharedSecrets;
47 import jdk.internal.util.StaticProperty;
48 import sun.security.util.*;
49 import sun.net.www.ParseUtil;
50
51 /**
52 * This class represents a default Policy implementation for the
53 * "JavaPolicy" type.
54 *
55 * <p> This object stores the policy for the entire Java runtime,
56 * and is the amalgamation of multiple static policy
57 * configurations that resides in files.
58 * The algorithm for locating the policy file(s) and reading their
59 * information into this <code>Policy</code> object is:
60 *
256 private boolean allowSystemProperties = true;
257 private boolean notUtf8 = false;
258 private URL url;
259
260 // for use with the reflection API
261 private static final Class<?>[] PARAMS0 = { };
262 private static final Class<?>[] PARAMS1 = { String.class };
263 private static final Class<?>[] PARAMS2 = { String.class, String.class };
264
265 /**
266 * When a policy file has a syntax error, the exception code may generate
267 * another permission check and this can cause the policy file to be parsed
268 * repeatedly, leading to a StackOverflowError or ClassCircularityError.
269 * To avoid this, this set is populated with policy files that have been
270 * previously parsed and have syntax errors, so that they can be
271 * subsequently ignored.
272 */
273 private static Set<URL> badPolicyURLs =
274 Collections.newSetFromMap(new ConcurrentHashMap<URL,Boolean>());
275
276 /**
277 * Initializes the Policy object and reads the default policy
278 * configuration file(s) into the Policy object.
279 */
280 public PolicyFile() {
281 init((URL)null);
282 }
283
284 /**
285 * Initializes the Policy object and reads the default policy
286 * from the specified URL only.
287 */
288 public PolicyFile(URL url) {
289 this.url = url;
290 init(url);
291 }
292
293 /**
294 * Initializes the Policy object and reads the default policy
295 * configuration file(s) into the Policy object.
315
316 int numCaches;
317 if (numCacheStr != null) {
318 try {
319 numCaches = Integer.parseInt(numCacheStr);
320 } catch (NumberFormatException e) {
321 numCaches = DEFAULT_CACHE_SIZE;
322 }
323 } else {
324 numCaches = DEFAULT_CACHE_SIZE;
325 }
326 // System.out.println("number caches=" + numCaches);
327 PolicyInfo newInfo = new PolicyInfo(numCaches);
328 initPolicyFile(newInfo, url);
329 policyInfo = newInfo;
330 }
331
332 private void initPolicyFile(final PolicyInfo newInfo, final URL url) {
333
334 // always load default.policy
335 AccessController.doPrivileged(new PrivilegedAction<>() {
336 @Override
337 public Void run() {
338 initDefaultPolicy(newInfo);
339 return null;
340 }
341 });
342
343 if (url != null) {
344
345 /**
346 * If the caller specified a URL via Policy.getInstance,
347 * we only read from default.policy and that URL.
348 */
349
350 if (debug != null) {
351 debug.println("reading " + url);
352 }
353 AccessController.doPrivileged(new PrivilegedAction<>() {
354 @Override
355 public Void run() {
356 if (init(url, newInfo) == false) {
357 // use static policy if all else fails
358 initStaticPolicy(newInfo);
359 }
360 return null;
361 }
362 });
363
364 } else {
365
366 /**
367 * Caller did not specify URL via Policy.getInstance.
368 * Read from URLs listed in the java.security properties file.
369 */
370
371 boolean loaded_one = initPolicyFile(POLICY, POLICY_URL, newInfo);
372 // To maintain strict backward compatibility
373 // we load the static policy only if POLICY load failed
374 if (!loaded_one) {
375 // use static policy if all else fails
376 initStaticPolicy(newInfo);
392 boolean overrideAll = false;
393 if (extra_policy.startsWith("=")) {
394 overrideAll = true;
395 extra_policy = extra_policy.substring(1);
396 }
397 try {
398 extra_policy =
399 PropertyExpander.expand(extra_policy);
400 URL policyURL;
401
402 File policyFile = new File(extra_policy);
403 if (policyFile.exists()) {
404 policyURL = ParseUtil.fileToEncodedURL
405 (new File(policyFile.getCanonicalPath()));
406 } else {
407 policyURL = new URL(extra_policy);
408 }
409 if (debug != null) {
410 debug.println("reading "+policyURL);
411 }
412 if (init(policyURL, newInfo)) {
413 loaded_policy = true;
414 }
415 } catch (Exception e) {
416 // ignore.
417 if (debug != null) {
418 debug.println("caught exception: "+e);
419 }
420 }
421 if (overrideAll) {
422 if (debug != null) {
423 debug.println("overriding other policies!");
424 }
425 return Boolean.valueOf(loaded_policy);
426 }
427 }
428 }
429
430 int n = 1;
431 String policy_uri;
432
435 URL policy_url = null;
436 String expanded_uri = PropertyExpander.expand
437 (policy_uri).replace(File.separatorChar, '/');
438
439 if (policy_uri.startsWith("file:${java.home}/") ||
440 policy_uri.startsWith("file:${user.home}/")) {
441
442 // this special case accommodates
443 // the situation java.home/user.home
444 // expand to a single slash, resulting in
445 // a file://foo URI
446 policy_url = new File
447 (expanded_uri.substring(5)).toURI().toURL();
448 } else {
449 policy_url = new URI(expanded_uri).toURL();
450 }
451
452 if (debug != null) {
453 debug.println("reading " + policy_url);
454 }
455 if (init(policy_url, newInfo)) {
456 loaded_policy = true;
457 }
458 } catch (Exception e) {
459 if (debug != null) {
460 debug.println(
461 "Debug info only. Error reading policy " +e);
462 e.printStackTrace();
463 }
464 // ignore that policy
465 }
466 n++;
467 }
468 return Boolean.valueOf(loaded_policy);
469 }
470 });
471
472 return loadedPolicy;
473 }
474
475 private void initDefaultPolicy(PolicyInfo newInfo) {
476 Path defaultPolicy = Path.of(StaticProperty.javaHome(),
477 "lib",
478 "security",
479 "default.policy");
480 if (debug != null) {
481 debug.println("reading " + defaultPolicy);
482 }
483 try (BufferedReader br = Files.newBufferedReader(defaultPolicy)) {
484
485 PolicyParser pp = new PolicyParser(expandProperties);
486 pp.read(br);
487
488 Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
489 while (enum_.hasMoreElements()) {
490 PolicyParser.GrantEntry ge = enum_.nextElement();
491 addGrantEntry(ge, null, newInfo);
492 }
493 } catch (Exception e) {
494 throw new InternalError("Failed to load default.policy", e);
495 }
496 }
497
498 /**
499 * Reads a policy configuration into the Policy object using a
500 * Reader object.
501 */
502 private boolean init(URL policy, PolicyInfo newInfo) {
503
504 // skip parsing policy file if it has been previously parsed and
505 // has syntax errors
506 if (badPolicyURLs.contains(policy)) {
507 if (debug != null) {
508 debug.println("skipping bad policy file: " + policy);
509 }
510 return false;
511 }
512
513 try (InputStreamReader isr =
514 getInputStreamReader(PolicyUtil.getInputStream(policy))) {
515
516 PolicyParser pp = new PolicyParser(expandProperties);
517 pp.read(isr);
518
519 KeyStore keyStore = null;
520 try {
521 keyStore = PolicyUtil.getKeyStore
522 (policy,
523 pp.getKeyStoreUrl(),
524 pp.getKeyStoreType(),
525 pp.getKeyStoreProvider(),
526 pp.getStorePassURL(),
527 debug);
528 } catch (Exception e) {
529 // ignore, treat it like we have no keystore
530 if (debug != null) {
531 debug.println("Debug info only. Ignoring exception.");
532 e.printStackTrace();
533 }
534 }
535
536 Enumeration<PolicyParser.GrantEntry> enum_ = pp.grantElements();
537 while (enum_.hasMoreElements()) {
538 PolicyParser.GrantEntry ge = enum_.nextElement();
539 addGrantEntry(ge, keyStore, newInfo);
540 }
541 return true;
542 } catch (PolicyParser.ParsingException pe) {
543 // record bad policy file to avoid later reparsing it
544 badPolicyURLs.add(policy);
545 Object[] source = {policy, pe.getNonlocalizedMessage()};
546 System.err.println(LocalizedMessage.getNonlocalized
547 (POLICY + ".error.parsing.policy.message", source));
548 if (debug != null) {
549 pe.printStackTrace();
550 }
551 } catch (Exception e) {
552 if (debug != null) {
553 debug.println("error parsing "+policy);
554 debug.println(e.toString());
555 e.printStackTrace();
556 }
557 }
558
559 return false;
560 }
561
562 private InputStreamReader getInputStreamReader(InputStream is)
563 throws IOException {
564 /*
565 * Read in policy using UTF-8 by default.
566 *
567 * Check non-standard system property to see if the default encoding
568 * should be used instead.
569 */
570 return (notUtf8)
571 ? new InputStreamReader(is)
|