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