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