1 /* 2 * Copyright (c) 1999, 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 com.sun.media.sound; 27 28 import java.io.Reader; 29 import java.nio.file.Files; 30 import java.nio.file.Path; 31 import java.nio.file.Paths; 32 import java.security.AccessController; 33 import java.security.PrivilegedAction; 34 import java.util.ArrayList; 35 import java.util.Iterator; 36 import java.util.List; 37 import java.util.Properties; 38 import java.util.ServiceLoader; 39 40 import javax.sound.sampled.AudioPermission; 41 42 /** Managing security in the Java Sound implementation. 43 * This class contains all code that uses and is used by 44 * SecurityManager.doPrivileged(). 45 * 46 * @author Matthias Pfisterer 47 */ 48 final class JSSecurityManager { 49 50 /** Prevent instantiation. 51 */ JSSecurityManager()52 private JSSecurityManager() { 53 } 54 checkRecordPermission()55 static void checkRecordPermission() throws SecurityException { 56 SecurityManager sm = System.getSecurityManager(); 57 if (sm != null) { 58 sm.checkPermission(new AudioPermission("record")); 59 } 60 } 61 62 /** 63 * Load properties from a file. 64 * <p> 65 * This method tries to load properties from the filename give into the 66 * passed properties object. If the file cannot be found or something else 67 * goes wrong, the method silently fails. 68 * <p> 69 * If the file referenced in "javax.sound.config.file" property exists and 70 * the user has an access to it, then it will be loaded, otherwise default 71 * configuration file "JAVA_HOME/conf/sound.properties" will be loaded. 72 * 73 * @param properties the properties bundle to store the values of the 74 * properties file 75 */ loadProperties(final Properties properties)76 static void loadProperties(final Properties properties) { 77 final String customFile = AccessController.doPrivileged( 78 (PrivilegedAction<String>) () -> System.getProperty( 79 "javax.sound.config.file")); 80 if (customFile != null) { 81 if (loadPropertiesImpl(properties, customFile)) { 82 return; 83 } 84 } 85 AccessController.doPrivileged((PrivilegedAction<Void>) () -> { 86 final String home = System.getProperty("java.home"); 87 if (home == null) { 88 throw new Error("Can't find java.home ??"); 89 } 90 loadPropertiesImpl(properties, home, "conf", "sound.properties"); 91 return null; 92 }); 93 } 94 loadPropertiesImpl(final Properties properties, String first, String... more)95 private static boolean loadPropertiesImpl(final Properties properties, 96 String first, String... more) { 97 final Path fname = Paths.get(first, more); 98 try (final Reader reader = Files.newBufferedReader(fname)) { 99 properties.load(reader); 100 return true; 101 } catch (final Throwable t) { 102 return false; 103 } 104 } 105 106 /** Create a Thread in the current ThreadGroup. 107 */ createThread(final Runnable runnable, final String threadName, final boolean isDaemon, final int priority, final boolean doStart)108 static Thread createThread(final Runnable runnable, 109 final String threadName, 110 final boolean isDaemon, final int priority, 111 final boolean doStart) 112 { 113 String name = (threadName != null) ? threadName : "JSSM Thread"; 114 Thread thread = new Thread(null, runnable, threadName, 0, false); 115 116 thread.setDaemon(isDaemon); 117 if (priority >= 0) { 118 thread.setPriority(priority); 119 } 120 if (doStart) { 121 thread.start(); 122 } 123 return thread; 124 } 125 getProviders(final Class<T> providerClass)126 static synchronized <T> List<T> getProviders(final Class<T> providerClass) { 127 List<T> p = new ArrayList<>(7); 128 // ServiceLoader creates "lazy" iterator instance, but it ensures that 129 // next/hasNext run with permissions that are restricted by whatever 130 // creates the ServiceLoader instance, so it requires to be called from 131 // privileged section 132 final PrivilegedAction<Iterator<T>> psAction = 133 new PrivilegedAction<Iterator<T>>() { 134 @Override 135 public Iterator<T> run() { 136 return ServiceLoader.load(providerClass).iterator(); 137 } 138 }; 139 final Iterator<T> ps = AccessController.doPrivileged(psAction); 140 141 // the iterator's hasNext() method looks through classpath for 142 // the provider class names, so it requires read permissions 143 PrivilegedAction<Boolean> hasNextAction = new PrivilegedAction<Boolean>() { 144 @Override 145 public Boolean run() { 146 return ps.hasNext(); 147 } 148 }; 149 150 while (AccessController.doPrivileged(hasNextAction)) { 151 try { 152 // the iterator's next() method creates instances of the 153 // providers and it should be called in the current security 154 // context 155 T provider = ps.next(); 156 if (providerClass.isInstance(provider)) { 157 // $$mp 2003-08-22 158 // Always adding at the beginning reverses the 159 // order of the providers. So we no longer have 160 // to do this in AudioSystem and MidiSystem. 161 p.add(0, provider); 162 } 163 } catch (Throwable t) { 164 //$$fb 2002-11-07: do not fail on SPI not found 165 if (Printer.err) t.printStackTrace(); 166 } 167 } 168 return p; 169 } 170 } 171