001: /* ***** BEGIN LICENSE BLOCK *****
002: * Version: MPL 1.1/GPL 2.0
003: *
004: * The contents of this file are subject to the Mozilla Public License Version
005: * 1.1 (the "License"); you may not use this file except in compliance with
006: * the License. You may obtain a copy of the License at
007: * http://www.mozilla.org/MPL/
008: *
009: * Software distributed under the License is distributed on an "AS IS" basis,
010: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
011: * for the specific language governing rights and limitations under the
012: * License.
013: *
014: * The Original Code is Rhino code, released May 6, 1999.
015: *
016: * The Initial Developer of the Original Code is
017: * Netscape Communications Corporation.
018: * Portions created by the Initial Developer are Copyright (C) 1997-1999
019: * the Initial Developer. All Rights Reserved.
020: *
021: * Contributor(s):
022: *
023: * Alternatively, the contents of this file may be used under the terms of
024: * the GNU General Public License Version 2 or later (the "GPL"), in which
025: * case the provisions of the GPL are applicable instead of those above. If
026: * you wish to allow use of your version of this file only under the terms of
027: * the GPL and not to allow others to use your version of this file under the
028: * MPL, indicate your decision by deleting the provisions above and replacing
029: * them with the notice and other provisions required by the GPL. If you do
030: * not delete the provisions above, a recipient may use your version of this
031: * file under either the MPL or the GPL.
032: *
033: * ***** END LICENSE BLOCK ***** */
034:
035: package org.mozilla.javascript;
036:
037: import java.io.ByteArrayOutputStream;
038: import java.io.IOException;
039: import java.io.InputStream;
040: import java.lang.ref.SoftReference;
041: import java.lang.reflect.UndeclaredThrowableException;
042: import java.net.URL;
043: import java.security.AccessController;
044: import java.security.CodeSource;
045: import java.security.PrivilegedAction;
046: import java.security.PrivilegedActionException;
047: import java.security.PrivilegedExceptionAction;
048: import java.security.SecureClassLoader;
049: import java.util.Map;
050: import java.util.WeakHashMap;
051:
052: /**
053: * @author Attila Szegedi
054: */
055: public abstract class SecureCaller {
056: private static final byte[] secureCallerImplBytecode = loadBytecode();
057:
058: // We're storing a CodeSource -> (ClassLoader -> SecureRenderer), since we
059: // need to have one renderer per class loader. We're using weak hash maps
060: // and soft references all the way, since we don't want to interfere with
061: // cleanup of either CodeSource or ClassLoader objects.
062: private static final Map callers = new WeakHashMap();
063:
064: public abstract Object call(Callable callable, Context cx,
065: Scriptable scope, Scriptable this Obj, Object[] args);
066:
067: /**
068: * Call the specified callable using a protection domain belonging to the
069: * specified code source.
070: */
071: static Object callSecurely(final CodeSource codeSource,
072: Callable callable, Context cx, Scriptable scope,
073: Scriptable this Obj, Object[] args) {
074: final Thread thread = Thread.currentThread();
075: // Run in doPrivileged as we might be checked for "getClassLoader"
076: // runtime permission
077: final ClassLoader classLoader = (ClassLoader) AccessController
078: .doPrivileged(new PrivilegedAction() {
079: public Object run() {
080: return thread.getContextClassLoader();
081: }
082: });
083: Map classLoaderMap;
084: synchronized (callers) {
085: classLoaderMap = (Map) callers.get(codeSource);
086: if (classLoaderMap == null) {
087: classLoaderMap = new WeakHashMap();
088: callers.put(codeSource, classLoaderMap);
089: }
090: }
091: SecureCaller caller;
092: synchronized (classLoaderMap) {
093: SoftReference ref = (SoftReference) classLoaderMap
094: .get(classLoader);
095: if (ref != null) {
096: caller = (SecureCaller) ref.get();
097: } else {
098: caller = null;
099: }
100: if (caller == null) {
101: try {
102: // Run in doPrivileged as we'll be checked for
103: // "createClassLoader" runtime permission
104: caller = (SecureCaller) AccessController
105: .doPrivileged(new PrivilegedExceptionAction() {
106: public Object run() throws Exception {
107: ClassLoader effectiveClassLoader;
108: Class this Class = getClass();
109: if (classLoader.loadClass(this Class
110: .getName()) != this Class) {
111: effectiveClassLoader = this Class
112: .getClassLoader();
113: } else {
114: effectiveClassLoader = classLoader;
115: }
116: SecureClassLoaderImpl secCl = new SecureClassLoaderImpl(
117: effectiveClassLoader);
118: Class c = secCl.defineAndLinkClass(
119: SecureCaller.class
120: .getName()
121: + "Impl",
122: secureCallerImplBytecode,
123: codeSource);
124: return c.newInstance();
125: }
126: });
127: classLoaderMap.put(classLoader, new SoftReference(
128: caller));
129: } catch (PrivilegedActionException ex) {
130: throw new UndeclaredThrowableException(ex
131: .getCause());
132: }
133: }
134: }
135: return caller.call(callable, cx, scope, this Obj, args);
136: }
137:
138: private static class SecureClassLoaderImpl extends
139: SecureClassLoader {
140: SecureClassLoaderImpl(ClassLoader parent) {
141: super (parent);
142: }
143:
144: Class defineAndLinkClass(String name, byte[] bytes,
145: CodeSource cs) {
146: Class cl = defineClass(name, bytes, 0, bytes.length, cs);
147: resolveClass(cl);
148: return cl;
149: }
150: }
151:
152: private static byte[] loadBytecode() {
153: return (byte[]) AccessController
154: .doPrivileged(new PrivilegedAction() {
155: public Object run() {
156: return loadBytecodePrivileged();
157: }
158: });
159: }
160:
161: private static byte[] loadBytecodePrivileged() {
162: URL url = SecureCaller.class
163: .getResource("SecureCallerImpl.clazz");
164: try {
165: InputStream in = url.openStream();
166: try {
167: ByteArrayOutputStream bout = new ByteArrayOutputStream();
168: for (;;) {
169: int r = in.read();
170: if (r == -1) {
171: return bout.toByteArray();
172: }
173: bout.write(r);
174: }
175: } finally {
176: in.close();
177: }
178: } catch (IOException e) {
179: throw new UndeclaredThrowableException(e);
180: }
181: }
182: }
|