001: /* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
002: *
003: * ***** BEGIN LICENSE BLOCK *****
004: * Version: MPL 1.1/GPL 2.0
005: *
006: * The contents of this file are subject to the Mozilla Public License Version
007: * 1.1 (the "License"); you may not use this file except in compliance with
008: * the License. You may obtain a copy of the License at
009: * http://www.mozilla.org/MPL/
010: *
011: * Software distributed under the License is distributed on an "AS IS" basis,
012: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
013: * for the specific language governing rights and limitations under the
014: * License.
015: *
016: * The Original Code is Rhino code, released
017: * May 6, 1999.
018: *
019: * The Initial Developer of the Original Code is
020: * Netscape Communications Corporation.
021: * Portions created by the Initial Developer are Copyright (C) 1997-1999
022: * the Initial Developer. All Rights Reserved.
023: *
024: * Contributor(s):
025: * Igor Bukanov
026: *
027: * Alternatively, the contents of this file may be used under the terms of
028: * the GNU General Public License Version 2 or later (the "GPL"), in which
029: * case the provisions of the GPL are applicable instead of those above. If
030: * you wish to allow use of your version of this file only under the terms of
031: * the GPL and not to allow others to use your version of this file under the
032: * MPL, indicate your decision by deleting the provisions above and replacing
033: * them with the notice and other provisions required by the GPL. If you do
034: * not delete the provisions above, a recipient may use your version of this
035: * file under either the MPL or the GPL.
036: *
037: * ***** END LICENSE BLOCK ***** */
038:
039: package org.mozilla.javascript.tools.shell;
040:
041: import java.security.*;
042: import java.net.MalformedURLException;
043: import java.net.URL;
044: import java.util.Enumeration;
045:
046: import org.mozilla.javascript.*;
047:
048: public class JavaPolicySecurity extends SecurityProxy {
049:
050: public Class getStaticSecurityDomainClassInternal() {
051: return ProtectionDomain.class;
052: }
053:
054: private static class Loader extends ClassLoader implements
055: GeneratedClassLoader {
056: private ProtectionDomain domain;
057:
058: Loader(ClassLoader parent, ProtectionDomain domain) {
059: super (parent != null ? parent : getSystemClassLoader());
060: this .domain = domain;
061: }
062:
063: public Class defineClass(String name, byte[] data) {
064: return super
065: .defineClass(name, data, 0, data.length, domain);
066: }
067:
068: public void linkClass(Class cl) {
069: resolveClass(cl);
070: }
071: }
072:
073: private static class ContextPermissions extends
074: PermissionCollection {
075: static final long serialVersionUID = -1721494496320750721L;
076:
077: // Construct PermissionCollection that permits an action only
078: // if it is permitted by staticDomain and by security context of Java stack on
079: // the moment of constructor invocation
080: ContextPermissions(ProtectionDomain staticDomain) {
081: _context = AccessController.getContext();
082: if (staticDomain != null) {
083: _statisPermissions = staticDomain.getPermissions();
084: }
085: setReadOnly();
086: }
087:
088: public void add(Permission permission) {
089: throw new RuntimeException("NOT IMPLEMENTED");
090: }
091:
092: public boolean implies(Permission permission) {
093: if (_statisPermissions != null) {
094: if (!_statisPermissions.implies(permission)) {
095: return false;
096: }
097: }
098: try {
099: _context.checkPermission(permission);
100: return true;
101: } catch (AccessControlException ex) {
102: return false;
103: }
104: }
105:
106: public Enumeration elements() {
107: return new Enumeration() {
108: public boolean hasMoreElements() {
109: return false;
110: }
111:
112: public Object nextElement() {
113: return null;
114: }
115: };
116: }
117:
118: public String toString() {
119: StringBuffer sb = new StringBuffer();
120: sb.append(getClass().getName());
121: sb.append('@');
122: sb.append(Integer
123: .toHexString(System.identityHashCode(this )));
124: sb.append(" (context=");
125: sb.append(_context);
126: sb.append(", static_permitions=");
127: sb.append(_statisPermissions);
128: sb.append(')');
129: return sb.toString();
130: }
131:
132: AccessControlContext _context;
133: PermissionCollection _statisPermissions;
134: }
135:
136: public JavaPolicySecurity() {
137: // To trigger error on jdk-1.1 with lazy load
138: new CodeSource(null, (java.security.cert.Certificate[]) null);
139: }
140:
141: protected void callProcessFileSecure(final Context cx,
142: final Scriptable scope, final String filename) {
143: AccessController.doPrivileged(new PrivilegedAction() {
144: public Object run() {
145: URL url = getUrlObj(filename);
146: ProtectionDomain staticDomain = getUrlDomain(url);
147: Main.processFileSecure(cx, scope, url.toExternalForm(),
148: staticDomain);
149: return null;
150: }
151: });
152: }
153:
154: private URL getUrlObj(String url) {
155: URL urlObj;
156: try {
157: urlObj = new URL(url);
158: } catch (MalformedURLException ex) {
159: // Assume as Main.processFileSecure it is file, need to build its
160: // URL
161: String curDir = System.getProperty("user.dir");
162: curDir = curDir.replace('\\', '/');
163: if (!curDir.endsWith("/")) {
164: curDir = curDir + '/';
165: }
166: try {
167: URL curDirURL = new URL("file:" + curDir);
168: urlObj = new URL(curDirURL, url);
169: } catch (MalformedURLException ex2) {
170: throw new RuntimeException(
171: "Can not construct file URL for '" + url + "':"
172: + ex2.getMessage());
173: }
174: }
175: return urlObj;
176: }
177:
178: private ProtectionDomain getUrlDomain(URL url) {
179: CodeSource cs;
180: cs = new CodeSource(url,
181: (java.security.cert.Certificate[]) null);
182: PermissionCollection pc = Policy.getPolicy().getPermissions(cs);
183: return new ProtectionDomain(cs, pc);
184: }
185:
186: public GeneratedClassLoader createClassLoader(
187: ClassLoader parentLoader, Object securityDomain) {
188: ProtectionDomain domain = (ProtectionDomain) securityDomain;
189: return new Loader(parentLoader, domain);
190: }
191:
192: public Object getDynamicSecurityDomain(Object securityDomain) {
193: ProtectionDomain staticDomain = (ProtectionDomain) securityDomain;
194: return getDynamicDomain(staticDomain);
195: }
196:
197: private ProtectionDomain getDynamicDomain(
198: ProtectionDomain staticDomain) {
199: ContextPermissions p = new ContextPermissions(staticDomain);
200: ProtectionDomain contextDomain = new ProtectionDomain(null, p);
201: return contextDomain;
202: }
203:
204: public Object callWithDomain(Object securityDomain,
205: final Context cx, final Callable callable,
206: final Scriptable scope, final Scriptable this Obj,
207: final Object[] args) {
208: ProtectionDomain staticDomain = (ProtectionDomain) securityDomain;
209: // There is no direct way in Java to intersect permitions according
210: // stack context with additional domain.
211: // The following implementation first constructs ProtectionDomain
212: // that allows actions only allowed by both staticDomain and current
213: // stack context, and then constructs AccessController for this dynamic
214: // domain.
215: // If this is too slow, alternative solution would be to generate
216: // class per domain with a proxy method to call to infect
217: // java stack.
218: // Another optimization in case of scripts coming from "world" domain,
219: // that is having minimal default privileges is to construct
220: // one AccessControlContext based on ProtectionDomain
221: // with least possible privileges and simply call
222: // AccessController.doPrivileged with this untrusted context
223:
224: ProtectionDomain dynamicDomain = getDynamicDomain(staticDomain);
225: ProtectionDomain[] tmp = { dynamicDomain };
226: AccessControlContext restricted = new AccessControlContext(tmp);
227:
228: PrivilegedAction action = new PrivilegedAction() {
229: public Object run() {
230: return callable.call(cx, scope, thisObj, args);
231: }
232: };
233:
234: return AccessController.doPrivileged(action, restricted);
235: }
236: }
|