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