1 /* 2 * Copyright (c) 1999, 2009, 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.BufferedInputStream; 29 import java.io.InputStream; 30 import java.io.File; 31 import java.io.FileInputStream; 32 33 import java.util.ArrayList; 34 import java.util.Iterator; 35 import java.util.List; 36 import java.util.Properties; 37 38 import java.security.AccessController; 39 import java.security.PrivilegedAction; 40 41 import javax.sound.sampled.AudioPermission; 42 43 import sun.misc.Service; 44 45 46 /** Managing security in the Java Sound implementation. 47 * This class contains all code that uses and is used by 48 * SecurityManager.doPrivileged(). 49 * 50 * @author Matthias Pfisterer 51 */ 52 class JSSecurityManager { 53 54 /** Prevent instantiation. 55 */ 56 private JSSecurityManager() { 57 } 58 59 /** Checks if the VM currently has a SecurityManager installed. 60 * Note that this may change over time. So the result of this method 61 * should not be cached. 62 * 63 * @return true if a SecurityManger is installed, false otherwise. 64 */ 65 private static boolean hasSecurityManager() { 66 return (System.getSecurityManager() != null); 67 } 68 69 70 static void checkRecordPermission() throws SecurityException { 71 if(Printer.trace) Printer.trace("JSSecurityManager.checkRecordPermission()"); 72 SecurityManager sm = System.getSecurityManager(); 73 if (sm != null) { 74 sm.checkPermission(new AudioPermission("record")); 75 } 76 } 77 78 79 static void loadLibrary(final String libName) { 80 try { 81 if (hasSecurityManager()) { 82 if(Printer.debug) Printer.debug("using security manager to load library"); 83 PrivilegedAction action = new PrivilegedAction() { 84 public Object run() { 85 System.loadLibrary(libName); 86 return null; 87 } 88 }; 89 AccessController.doPrivileged(action); 90 } else { 91 if(Printer.debug) Printer.debug("not using security manager to load library"); 92 System.loadLibrary(libName); 93 } 94 if (Printer.debug) Printer.debug("loaded library " + libName); 95 } catch (UnsatisfiedLinkError e2) { 96 if (Printer.err)Printer.err("UnsatisfiedLinkError loading native library " + libName); 97 throw(e2); 98 } 99 } 100 101 102 static String getProperty(final String propertyName) { 103 String propertyValue; 104 if (hasSecurityManager()) { 105 if(Printer.debug) Printer.debug("using JDK 1.2 security to get property"); 106 try{ 107 PrivilegedAction action = new PrivilegedAction() { 108 public Object run() { 109 try { 110 return System.getProperty(propertyName); 111 } catch (Throwable t) { 112 return null; 113 } 114 } 115 }; 116 propertyValue = (String) AccessController.doPrivileged(action); 117 } catch( Exception e ) { 118 if(Printer.debug) Printer.debug("not using JDK 1.2 security to get properties"); 119 propertyValue = System.getProperty(propertyName); 120 } 121 } else { 122 if(Printer.debug) Printer.debug("not using JDK 1.2 security to get properties"); 123 propertyValue = System.getProperty(propertyName); 124 } 125 return propertyValue; 126 } 127 128 129 /** Load properties from a file. 130 This method tries to load properties from the filename give into 131 the passed properties object. 132 If the file cannot be found or something else goes wrong, 133 the method silently fails. 134 @param properties The properties bundle to store the values of the 135 properties file. 136 @param filename The filename of the properties file to load. This 137 filename is interpreted as relative to the subdirectory "lib" in 138 the JRE directory. 139 */ 140 static void loadProperties(final Properties properties, 141 final String filename) { 142 if(hasSecurityManager()) { 143 try { 144 // invoke the privileged action using 1.2 security 145 PrivilegedAction action = new PrivilegedAction() { 146 public Object run() { 147 loadPropertiesImpl(properties, filename); 148 return null; 149 } 150 }; 151 AccessController.doPrivileged(action); 152 if(Printer.debug)Printer.debug("Loaded properties with JDK 1.2 security"); 153 } catch (Exception e) { 154 if(Printer.debug)Printer.debug("Exception loading properties with JDK 1.2 security"); 155 // try without using JDK 1.2 security 156 loadPropertiesImpl(properties, filename); 157 } 158 } else { 159 // not JDK 1.2 security, assume we already have permission 160 loadPropertiesImpl(properties, filename); 161 } 162 } 163 164 165 private static void loadPropertiesImpl(Properties properties, 166 String filename) { 167 if(Printer.trace)Printer.trace(">> JSSecurityManager: loadPropertiesImpl()"); 168 String fname = System.getProperty("java.home"); 169 try { 170 if (fname == null) { 171 throw new Error("Can't find java.home ??"); 172 } 173 File f = new File(fname, "lib"); 174 f = new File(f, filename); 175 fname = f.getCanonicalPath(); 176 InputStream in = new FileInputStream(fname); 177 BufferedInputStream bin = new BufferedInputStream(in); 178 try { 179 properties.load(bin); 180 } finally { 181 if (in != null) { 182 in.close(); 183 } 184 } 185 } catch (Throwable t) { 186 if (Printer.trace) { 187 System.err.println("Could not load properties file \"" + fname + "\""); 188 t.printStackTrace(); 189 } 190 } 191 if(Printer.trace)Printer.trace("<< JSSecurityManager: loadPropertiesImpl() completed"); 192 } 193 194 195 private static ThreadGroup getTopmostThreadGroup() { 196 ThreadGroup topmostThreadGroup; 197 if(hasSecurityManager()) { 198 try { 199 // invoke the privileged action using 1.2 security 200 PrivilegedAction action = new PrivilegedAction() { 201 public Object run() { 202 try { 203 return getTopmostThreadGroupImpl(); 204 } catch (Throwable t) { 205 return null; 206 } 207 } 208 }; 209 topmostThreadGroup = (ThreadGroup) AccessController.doPrivileged(action); 210 if(Printer.debug)Printer.debug("Got topmost thread group with JDK 1.2 security"); 211 } catch (Exception e) { 212 if(Printer.debug)Printer.debug("Exception getting topmost thread group with JDK 1.2 security"); 213 // try without using JDK 1.2 security 214 topmostThreadGroup = getTopmostThreadGroupImpl(); 215 } 216 } else { 217 // not JDK 1.2 security, assume we already have permission 218 topmostThreadGroup = getTopmostThreadGroupImpl(); 219 } 220 return topmostThreadGroup; 221 } 222 223 224 private static ThreadGroup getTopmostThreadGroupImpl() { 225 if(Printer.trace)Printer.trace(">> JSSecurityManager: getTopmostThreadGroupImpl()"); 226 ThreadGroup g = Thread.currentThread().getThreadGroup(); 227 while ((g.getParent() != null) && (g.getParent().getParent() != null)) { 228 g = g.getParent(); 229 } 230 if(Printer.trace)Printer.trace("<< JSSecurityManager: getTopmostThreadGroupImpl() completed"); 231 return g; 232 } 233 234 235 /** Create a Thread in the topmost ThreadGroup. 236 */ 237 static Thread createThread(final Runnable runnable, 238 final String threadName, 239 final boolean isDaemon, final int priority, 240 final boolean doStart) { 241 Thread thread = null; 242 if(hasSecurityManager()) { 243 PrivilegedAction action = new PrivilegedAction() { 244 public Object run() { 245 try { 246 return createThreadImpl(runnable, threadName, 247 isDaemon, priority, 248 doStart); 249 } catch (Throwable t) { 250 return null; 251 } 252 } 253 }; 254 thread = (Thread) AccessController.doPrivileged(action); 255 if(Printer.debug) Printer.debug("created thread with JDK 1.2 security"); 256 } else { 257 if(Printer.debug)Printer.debug("not using JDK 1.2 security"); 258 thread = createThreadImpl(runnable, threadName, isDaemon, priority, 259 doStart); 260 } 261 return thread; 262 } 263 264 265 private static Thread createThreadImpl(Runnable runnable, 266 String threadName, 267 boolean isDaemon, int priority, 268 boolean doStart) { 269 ThreadGroup threadGroup = getTopmostThreadGroupImpl(); 270 Thread thread = new Thread(threadGroup, runnable); 271 if (threadName != null) { 272 thread.setName(threadName); 273 } 274 thread.setDaemon(isDaemon); 275 if (priority >= 0) { 276 thread.setPriority(priority); 277 } 278 if (doStart) { 279 thread.start(); 280 } 281 return thread; 282 } 283 284 285 static List getProviders(final Class providerClass) { 286 List p = new ArrayList(); 287 // Service.providers(Class) just creates "lazy" iterator instance, 288 // so it doesn't require do be called from privileged section 289 final Iterator ps = Service.providers(providerClass); 290 291 // the iterator's hasNext() method looks through classpath for 292 // the provider class names, so it requires read permissions 293 PrivilegedAction<Boolean> hasNextAction = new PrivilegedAction<Boolean>() { 294 public Boolean run() { 295 return ps.hasNext(); 296 } 297 }; 298 299 while (AccessController.doPrivileged(hasNextAction)) { 300 try { 301 // the iterator's next() method creates instances of the 302 // providers and it should be called in the current security 303 // context 304 Object provider = ps.next(); 305 if (providerClass.isInstance(provider)) { 306 // $$mp 2003-08-22 307 // Always adding at the beginning reverses the 308 // order of the providers. So we no longer have 309 // to do this in AudioSystem and MidiSystem. 310 p.add(0, provider); 311 } 312 } catch (Throwable t) { 313 //$$fb 2002-11-07: do not fail on SPI not found 314 if (Printer.err) t.printStackTrace(); 315 } 316 } 317 return p; 318 } 319 }