1/*
2 * Copyright (c) 1995, 2017, 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
26package sun.applet;
27
28import java.io.File;
29import java.io.FilePermission;
30import java.io.IOException;
31import java.io.FileDescriptor;
32import java.net.URL;
33import java.net.URLClassLoader;
34import java.net.InetAddress;
35import java.net.UnknownHostException;
36import java.net.SocketPermission;
37import java.util.Enumeration;
38import java.util.Iterator;
39import java.util.HashSet;
40import java.util.StringTokenizer;
41import java.security.*;
42import java.lang.reflect.*;
43import jdk.internal.misc.JavaNetURLClassLoaderAccess;
44import jdk.internal.misc.JavaSecurityAccess;
45import jdk.internal.misc.SharedSecrets;
46import sun.awt.AWTSecurityManager;
47import sun.awt.AppContext;
48import sun.awt.AWTPermissions;
49import sun.security.util.SecurityConstants;
50
51
52
53/**
54 * This class defines an applet security policy
55 *
56 */
57public
58class 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
365