1 /*
   2  * Copyright (c) 1995, 2014, 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.applet;
  27 
  28 import java.io.File;
  29 import java.io.FilePermission;
  30 import java.io.IOException;
  31 import java.io.FileDescriptor;
  32 import java.net.URL;
  33 import java.net.URLClassLoader;
  34 import java.net.InetAddress;
  35 import java.net.UnknownHostException;
  36 import java.net.SocketPermission;
  37 import java.util.Enumeration;
  38 import java.util.Iterator;
  39 import java.util.HashSet;
  40 import java.util.StringTokenizer;
  41 import java.security.*;
  42 import java.lang.reflect.*;
  43 import sun.awt.AWTSecurityManager;
  44 import sun.awt.AppContext;
  45 import sun.awt.AWTPermissions;
  46 import sun.security.provider.*;
  47 import sun.security.util.SecurityConstants;
  48 
  49 
  50 /**
  51  * This class defines an applet security policy
  52  *
  53  */
  54 public
  55 class AppletSecurity extends AWTSecurityManager {
  56 
  57     //URLClassLoader.acc
  58     private static Field facc = null;
  59 
  60     //AccessControlContext.context;
  61     private static Field fcontext = null;
  62 
  63     static {
  64         try {
  65             facc = URLClassLoader.class.getDeclaredField("acc");
  66             facc.setAccessible(true);
  67             fcontext = AccessControlContext.class.getDeclaredField("context");
  68             fcontext.setAccessible(true);
  69         } catch (NoSuchFieldException e) {
  70             throw new UnsupportedOperationException(e);
  71         }
  72     }
  73 
  74 
  75     /**
  76      * Construct and initialize.
  77      */
  78     public AppletSecurity() {
  79         reset();
  80     }
  81 
  82     // Cache to store known restricted packages
  83     private HashSet<String> restrictedPackages = new HashSet<>();
  84 
  85     /**
  86      * Reset from Properties
  87      */
  88     public void reset()
  89     {
  90         // Clear cache
  91         restrictedPackages.clear();
  92 
  93         AccessController.doPrivileged(new PrivilegedAction<Object>() {
  94             public Object run()
  95             {
  96                 // Enumerate system properties
  97                 Enumeration<?> e = System.getProperties().propertyNames();
  98 
  99                 while (e.hasMoreElements())
 100                 {
 101                     String name = (String) e.nextElement();
 102 
 103                     if (name != null && name.startsWith("package.restrict.access."))
 104                     {
 105                         String value = System.getProperty(name);
 106 
 107                         if (value != null && value.equalsIgnoreCase("true"))
 108                         {
 109                             String pkg = name.substring(24);
 110 
 111                             // Cache restricted packages
 112                             restrictedPackages.add(pkg);
 113                         }
 114                     }
 115                 }
 116                 return null;
 117             }
 118         });
 119     }
 120 
 121     /**
 122      * get the current (first) instance of an AppletClassLoader on the stack.
 123      */
 124     @SuppressWarnings("deprecation")
 125     private AppletClassLoader currentAppletClassLoader()
 126     {
 127         // try currentClassLoader first
 128         ClassLoader loader = currentClassLoader();
 129 
 130         if ((loader == null) || (loader instanceof AppletClassLoader))
 131             return (AppletClassLoader)loader;
 132 
 133         // if that fails, get all the classes on the stack and check them.
 134         Class<?>[] context = getClassContext();
 135         for (int i = 0; i < context.length; i++) {
 136             loader = context[i].getClassLoader();
 137             if (loader instanceof AppletClassLoader)
 138                 return (AppletClassLoader)loader;
 139         }
 140 
 141         /*
 142          * fix bug # 6433620 the logic here is : try to find URLClassLoader from
 143          * class context, check its AccessControlContext to see if
 144          * AppletClassLoader is in stack when it's created. for this kind of
 145          * URLClassLoader, return the AppContext associated with the
 146          * AppletClassLoader.
 147          */
 148         for (int i = 0; i < context.length; i++) {
 149             final ClassLoader currentLoader = context[i].getClassLoader();
 150 
 151             if (currentLoader instanceof URLClassLoader) {
 152                 loader = AccessController.doPrivileged(
 153                     new PrivilegedAction<ClassLoader>() {
 154                         public ClassLoader run() {
 155 
 156                             AccessControlContext acc = null;
 157                             ProtectionDomain[] pds = null;
 158 
 159                             try {
 160                                 acc = (AccessControlContext) facc.get(currentLoader);
 161                                 if (acc == null) {
 162                                     return null;
 163                                 }
 164 
 165                                 pds = (ProtectionDomain[]) fcontext.get(acc);
 166                                 if (pds == null) {
 167                                     return null;
 168                                 }
 169                             } catch (Exception e) {
 170                                 throw new UnsupportedOperationException(e);
 171                             }
 172 
 173                             for (int i=0; i<pds.length; i++) {
 174                                 ClassLoader cl = pds[i].getClassLoader();
 175 
 176                                 if (cl instanceof AppletClassLoader) {
 177                                         return cl;
 178                                 }
 179                             }
 180 
 181                             return null;
 182                         }
 183                     });
 184 
 185                 if (loader != null) {
 186                     return (AppletClassLoader) loader;
 187                 }
 188             }
 189         }
 190 
 191         // if that fails, try the context class loader
 192         loader = Thread.currentThread().getContextClassLoader();
 193         if (loader instanceof AppletClassLoader)
 194             return (AppletClassLoader)loader;
 195 
 196         // no AppletClassLoaders on the stack
 197         return (AppletClassLoader)null;
 198     }
 199 
 200     /**
 201      * Returns true if this threadgroup is in the applet's own thread
 202      * group. This will return false if there is no current class
 203      * loader.
 204      */
 205     protected boolean inThreadGroup(ThreadGroup g) {
 206         if (currentAppletClassLoader() == null)
 207             return false;
 208         else
 209             return getThreadGroup().parentOf(g);
 210     }
 211 
 212     /**
 213      * Returns true of the threadgroup of thread is in the applet's
 214      * own threadgroup.
 215      */
 216     protected boolean inThreadGroup(Thread thread) {
 217         return inThreadGroup(thread.getThreadGroup());
 218     }
 219 
 220     /**
 221      * Applets are not allowed to manipulate threads outside
 222      * applet thread groups. However a terminated thread no longer belongs
 223      * to any group.
 224      */
 225     public void checkAccess(Thread t) {
 226         /* When multiple applets is reloaded simultaneously, there will be
 227          * multiple invocations to this method from plugin's SecurityManager.
 228          * This method should not be synchronized to avoid deadlock when
 229          * a page with multiple applets is reloaded
 230          */
 231         if ((t.getState() != Thread.State.TERMINATED) && !inThreadGroup(t)) {
 232             checkPermission(SecurityConstants.MODIFY_THREAD_PERMISSION);
 233         }
 234     }
 235 
 236     private boolean inThreadGroupCheck = false;
 237 
 238     /**
 239      * Applets are not allowed to manipulate thread groups outside
 240      * applet thread groups.
 241      */
 242     public synchronized void checkAccess(ThreadGroup g) {
 243         if (inThreadGroupCheck) {
 244             // if we are in a recursive check, it is because
 245             // inThreadGroup is calling appletLoader.getThreadGroup
 246             // in that case, only do the super check, as appletLoader
 247             // has a begin/endPrivileged
 248             checkPermission(SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
 249         } else {
 250             try {
 251                 inThreadGroupCheck = true;
 252                 if (!inThreadGroup(g)) {
 253                     checkPermission(SecurityConstants.MODIFY_THREADGROUP_PERMISSION);
 254                 }
 255             } finally {
 256                 inThreadGroupCheck = false;
 257             }
 258         }
 259     }
 260 
 261 
 262     /**
 263      * Throws a <code>SecurityException</code> if the
 264      * calling thread is not allowed to access the package specified by
 265      * the argument.
 266      * <p>
 267      * This method is used by the <code>loadClass</code> method of class
 268      * loaders.
 269      * <p>
 270      * The <code>checkPackageAccess</code> method for class
 271      * <code>SecurityManager</code>  calls
 272      * <code>checkPermission</code> with the
 273      * <code>RuntimePermission("accessClassInPackage."+pkg)</code>
 274      * permission.
 275      *
 276      * @param      pkg   the package name.
 277      * @exception  SecurityException  if the caller does not have
 278      *             permission to access the specified package.
 279      * @see        java.lang.ClassLoader#loadClass(java.lang.String, boolean)
 280      */
 281     public void checkPackageAccess(final String pkgname) {
 282 
 283         // first see if the VM-wide policy allows access to this package
 284         super.checkPackageAccess(pkgname);
 285 
 286         // now check the list of restricted packages
 287         for (Iterator<String> iter = restrictedPackages.iterator(); iter.hasNext();)
 288         {
 289             String pkg = iter.next();
 290 
 291             // Prevent matching "sun" and "sunir" even if they
 292             // starts with similar beginning characters
 293             //
 294             if (pkgname.equals(pkg) || pkgname.startsWith(pkg + "."))
 295             {
 296                 checkPermission(new java.lang.RuntimePermission
 297                             ("accessClassInPackage." + pkgname));
 298             }
 299         }
 300     }
 301 
 302     /**
 303      * Tests if a client can get access to the AWT event queue.
 304      * <p>
 305      * This method calls <code>checkPermission</code> with the
 306      * <code>AWTPermission("accessEventQueue")</code> permission.
 307      *
 308      * @since   1.1
 309      * @exception  SecurityException  if the caller does not have
 310      *             permission to access the AWT event queue.
 311      */
 312     @SuppressWarnings("deprecation")
 313     public void checkAwtEventQueueAccess() {
 314         AppContext appContext = AppContext.getAppContext();
 315         AppletClassLoader appletClassLoader = currentAppletClassLoader();
 316 
 317         if (AppContext.isMainContext(appContext) && (appletClassLoader != null)) {
 318             // If we're about to allow access to the main EventQueue,
 319             // and anything untrusted is on the class context stack,
 320             // disallow access.
 321             super.checkPermission(AWTPermissions.CHECK_AWT_EVENTQUEUE_PERMISSION);
 322         }
 323     } // checkAwtEventQueueAccess()
 324 
 325     /**
 326      * Returns the thread group of the applet. We consult the classloader
 327      * if there is one.
 328      */
 329     public ThreadGroup getThreadGroup() {
 330         /* If any applet code is on the execution stack, we return
 331            that applet's ThreadGroup.  Otherwise, we use the default
 332            behavior. */
 333         AppletClassLoader appletLoader = currentAppletClassLoader();
 334         ThreadGroup loaderGroup = (appletLoader == null) ? null
 335                                           : appletLoader.getThreadGroup();
 336         if (loaderGroup != null) {
 337             return loaderGroup;
 338         } else {
 339             return super.getThreadGroup();
 340         }
 341     } // getThreadGroup()
 342 
 343     /**
 344       * Get the AppContext corresponding to the current context.
 345       * The default implementation returns null, but this method
 346       * may be overridden by various SecurityManagers
 347       * (e.g. AppletSecurity) to index AppContext objects by the
 348       * calling context.
 349       *
 350       * @return  the AppContext corresponding to the current context.
 351       * @see     sun.awt.AppContext
 352       * @see     java.lang.SecurityManager
 353       * @since   1.2.1
 354       */
 355     public AppContext getAppContext() {
 356         AppletClassLoader appletLoader = currentAppletClassLoader();
 357 
 358         if (appletLoader == null) {
 359             return null;
 360         } else {
 361             AppContext context =  appletLoader.getAppContext();
 362 
 363             // context == null when some thread in applet thread group
 364             // has not been destroyed in AppContext.dispose()
 365             if (context == null) {
 366                 throw new SecurityException("Applet classloader has invalid AppContext");
 367             }
 368 
 369             return context;
 370         }
 371     }
 372 
 373 } // class AppletSecurity