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 }