Index: gnu/java/security/PolicyFile.java =================================================================== RCS file: gnu/java/security/PolicyFile.java diff -N gnu/java/security/PolicyFile.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ gnu/java/security/PolicyFile.java 3 Jun 2004 09:10:37 -0000 @@ -0,0 +1,665 @@ +/* PolicyFile.java -- policy file reader. + Copyright (C) 2004 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StreamTokenizer; +import java.lang.reflect.Constructor; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.Security; +import java.security.UnresolvedPermission; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +/** + * An implementation of a address@hidden java.security.Policy} object whose + * permissions are specified by a policy file. + * + *
The approximate syntax of policy files is:
+ * + *+ * policyFile ::= keystoreOrGrantEntries ; + * + * keystoreOrGrantEntries ::= keystoreOrGrantEntry | + * keystoreOrGrantEntries keystoreOrGrantEntry | + * EMPTY ; + * + * keystoreOrGrantEntry ::= keystoreEntry | grantEntry ; + * + * keystoreEntry ::= "keystore" keystoreUrl ';' | + * "keystore" keystoreUrl ',' keystoreAlgorithm ';' ; + * + * keystoreUrl ::= URL ; + * keystoreAlgorithm ::= STRING ; + * + * grantEntry ::= "grant" domainParameters '{' permissions '}' ';' + * + * domainParameters ::= domainParameter | + * domainParameter ',' domainParameters ; + * + * domainParameter ::= "signedBy" signerNames | + * "codeBase" codeBaseUrl | + * "principal" principalClassName principalName | + * "principal" principalName ; + * + * signerNames ::= quotedString ; + * codeBaseUrl ::= URL ; + * principalClassName ::= STRING ; + * principalName ::= quotedString ; + * + * quotedString ::= quoteChar STRING quoteChar ; + * quoteChar ::= '"' | '\''; + * + * permissions ::= permission | permissions permission ; + * + * permission ::= "permission" permissionClassName permissionTarget permissionAction | + * "permission" permissionClassName permissionTarget | + * "permission" permissionClassName; + *+ * + *
Comments are either form of Java comments. Keystore entries only
+ * affect subsequent grant entries, so if a grant entry preceeds a
+ * keystore entry, that grant entry is not affected by that keystore
+ * entry. Certian instances of ${property-name}
will be
+ * replaced with System.getProperty("property-name")
in
+ * quoted strings.
This class will load the following files when created or + * refreshed, in order:
+ * + *${java.home}/lib/security/java.policy
."policy.file.n"
, for increasing n
+ * starting from 1. The sequence stops at the first undefined
+ * property, so you must set "policy.file.1"
if you also
+ * set "policy.file.2"
, and so on."java.security.policy"
."${property-name}"
into
+ * System.getProperty("property-name")
.
+ */
+ private static String expand(final String s)
+ {
+ final StringBuffer result = new StringBuffer();
+ final StringBuffer prop = new StringBuffer();
+ int state = 0;
+ for (int i = 0; i < s.length(); i++)
+ {
+ switch (state)
+ {
+ case 0:
+ if (s.charAt(i) == '$')
+ state = 1;
+ else
+ result.append(s.charAt(i));
+ break;
+ case 1:
+ if (s.charAt(i) == '{')
+ state = 2;
+ else
+ {
+ state = 0;
+ result.append('$').append(s.charAt(i));
+ }
+ break;
+ case 2:
+ if (s.charAt(i) == '}')
+ {
+ String p = prop.toString();
+ if (p.equals("/"))
+ p = "file.separator";
+ p = System.getProperty(p);
+ if (p == null)
+ p = "";
+ result.append(p);
+ prop.setLength(0);
+ state = 0;
+ }
+ else
+ prop.append(s.charAt(i));
+ break;
+ }
+ }
+ if (state != 0)
+ result.append('$').append('{').append(prop);
+ return result.toString();
+ }
+
+ /**
+ * I miss macros.
+ */
+ private static void error(URL base, StreamTokenizer in, String msg)
+ throws IOException
+ {
+ throw new IOException(base+":"+in.lineno()+": "+msg);
+ }
+}
Index: gnu/java/security/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/security/Makefile.am,v
retrieving revision 1.6
diff -u -b -B -r1.6 Makefile.am
--- gnu/java/security/Makefile.am 23 Apr 2003 23:02:38 -0000 1.6
+++ gnu/java/security/Makefile.am 3 Jun 2004 09:10:37 -0000
@@ -4,5 +4,6 @@
EXTRA_DIST = \
Engine.java \
-OID.java
+OID.java \
+PolicyFile.java
Index: java/security/IntersectingDomainCombiner.java
===================================================================
RCS file: java/security/IntersectingDomainCombiner.java
diff -N java/security/IntersectingDomainCombiner.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ java/security/IntersectingDomainCombiner.java 3 Jun 2004 09:10:37 -0000
@@ -0,0 +1,82 @@
+/* IntersectingDomainCombiner.java --
+ Copyright (C) 2004 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+02111-1307 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.security;
+
+import java.util.HashSet;
+
+/**
+ * A trivial implementation of address@hidden DomainCombiner} that produces the
+ * intersection of the supplied address@hidden ProtectionDomain} objects.
+ */
+final class IntersectingDomainCombiner implements DomainCombiner
+{
+
+ // Contstant.
+ // -------------------------------------------------------------------------
+
+ static final IntersectingDomainCombiner SINGLETON = new IntersectingDomainCombiner();
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ private IntersectingDomainCombiner()
+ {
+ }
+
+ // Methods.
+ // -------------------------------------------------------------------------
+
+ public ProtectionDomain[] combine (ProtectionDomain[] currentDomains,
+ ProtectionDomain[] assignedDomains)
+ {
+ HashSet newDomains = new HashSet ();
+ for (int i = 0; i < currentDomains.length; i++)
+ {
+ if (currentDomains[i] == null)
+ continue;
+ for (int j = 0; j < assignedDomains.length; j++)
+ {
+ if (currentDomains[i].equals (assignedDomains[j]))
+ newDomains.add (currentDomains[i]);
+ }
+ }
+ return (ProtectionDomain[])
+ newDomains.toArray(new ProtectionDomain[newDomains.size()]);
+ }
+}
Index: java/security/Makefile.am
===================================================================
RCS file: /cvsroot/classpath/classpath/java/security/Makefile.am,v
retrieving revision 1.8
diff -u -b -B -r1.8 Makefile.am
--- java/security/Makefile.am 6 May 2002 21:10:53 -0000 1.8
+++ java/security/Makefile.am 3 Jun 2004 09:10:37 -0000
@@ -26,6 +26,7 @@
Guard.java \
Identity.java \
IdentityScope.java \
+IntersectingDomainCombiner.java \
InvalidAlgorithmParameterException.java \
InvalidKeyException.java \
InvalidParameterException.java \
Index: java/security/AccessController.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/security/AccessController.java,v
retrieving revision 1.7
diff -u -b -B -r1.7 AccessController.java
--- java/security/AccessController.java 20 Apr 2004 19:18:15 -0000 1.7
+++ java/security/AccessController.java 3 Jun 2004 09:10:38 -0000
@@ -115,8 +115,16 @@
public static Object doPrivileged(PrivilegedAction action,
AccessControlContext context)
{
+ VMAccessController.pushContext (context, action.getClass());
+ try
+ {
return action.run();
}
+ finally
+ {
+ VMAccessController.popContext (action.getClass());
+ }
+ }
/**
* Calls the run()
method of the given action with as
@@ -170,6 +178,7 @@
AccessControlContext context)
throws PrivilegedActionException
{
+ VMAccessController.pushContext (context, action.getClass());
try
{
@@ -179,19 +188,28 @@
{
throw new PrivilegedActionException(e);
}
+ finally
+ {
+ VMAccessController.popContext (action.getClass());
+ }
}
/**
* Returns the complete access control context of the current thread.
- *
- * XXX - Should this include all the protection domains in the call chain
- * or only the domains till the last doPrivileged()
call?
- *
- * XXX - needs native support. Currently returns an empty context. + * The returned object encompasses all address@hidden ProtectionDomain} objects + * for all classes in the current call stack, or the set of protection + * domains until the last call to address@hidden + * #doPrivileged(java.security.PrivilegedAction)}. + * + *
Additionally, if a call was made to address@hidden + * #doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)} + * that supplied an address@hidden AccessControlContext}, then that context + * will be intersected with the calculated one. + * + * @return The context. */ public static AccessControlContext getContext() { - // For now just return an new empty context - return new AccessControlContext(new ProtectionDomain[0]); + return VMAccessController.getContext(); } } Index: vm/reference/java/security/VMAccessController.java =================================================================== RCS file: vm/reference/java/security/VMAccessController.java diff -N vm/reference/java/security/VMAccessController.java --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ vm/reference/java/security/VMAccessController.java 3 Jun 2004 09:10:38 -0000 @@ -0,0 +1,236 @@ +/* VMAccessController.java -- VM-specific access controller methods. + Copyright (C) 2004 Free Software Foundation, Inc. + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +This program is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package java.security; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +final class VMAccessController +{ + + // Fields. + // ------------------------------------------------------------------------- + + /** + * A mapping between pairs (thread, classname) to access + * control contexts. The thread and classname are the thread + * and classname current as of the last call to doPrivileged with + * an AccessControlContext argument. + */ + private static final Map contexts = Collections.synchronizedMap(new HashMap()); + + private static final ThreadLocal inGetContext = new ThreadLocal(); + + private final static AccessControlContext DEFAULT_CONTEXT; + static + { + CodeSource source = new CodeSource(null, null); + Permissions permissions = new Permissions(); + permissions.add(new AllPermission()); + ProtectionDomain[] domain = new ProtectionDomain[] { + new ProtectionDomain(source, permissions) + }; + DEFAULT_CONTEXT = new AccessControlContext(domain); + } + + private static final boolean DEBUG = false; + private static void debug (String msg) + { + System.err.print (">>> VMAccessController: "); + System.err.println (msg); + } + + // Constructors. + // ------------------------------------------------------------------------- + + private VMAccessController() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Relate a class (which should be an instance of address@hidden PrivilegedAction} + * with an access control context. This method is used by address@hidden + * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)} + * to set up the context that will be returned by address@hidden #getContext()}. + * This method relates the class to the current thread, so contexts + * pushed from one thread will not be available to another. + * + * @param acc The access control context. + * @param clazz The class that implements address@hidden PrivilegedAction}. + */ + static void pushContext (AccessControlContext acc, Class clazz) + { + ArrayList pair = new ArrayList (2); + pair.add (Thread.currentThread()); + pair.add (clazz); + if (DEBUG) debug ("pushing " + pair); + contexts.put (pair, acc); + } + + /** + * Removes the relation of a class to an address@hidden AccessControlContext}. + * This method is used by address@hidden AccessController} when exiting from a + * call to address@hidden + * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}. + * + * @param clazz The class that implements address@hidden PrivilegedAction}. + */ + static void popContext (Class clazz) + { + ArrayList pair = new ArrayList (2); + pair.add (Thread.currentThread()); + pair.add (clazz); + if (DEBUG) debug ("popping " + pair); + contexts.remove (pair); + } + + /** + * Examine the method stack of the currently running thread, and create + * an address@hidden AccessControlContext} filled in with the appropriate address@hidden + * ProtectionDomain} objects given this stack. + * + * @return The context. + */ + static AccessControlContext getContext() + { + // If we are already in getContext, but called a method that needs + // a permission check, return the all-permissive context so methods + // called from here succeed. + // + // XXX is this necessary? We should verify if there are any calls in + // the stack below this method that require permission checks. + Boolean inCall = (Boolean) inGetContext.get(); + if (inCall != null && inCall.booleanValue()) + { + if (DEBUG) debug ("already in getContext"); + return DEFAULT_CONTEXT; + } + + Object[][] stack = getStack(); + Class[] classes = (Class[]) stack[0]; + String[] methods = (String[]) stack[1]; + + inGetContext.set (Boolean.TRUE); + + if (DEBUG) debug (">>> got trace of length " + classes.length); + + HashSet domains = new HashSet(); + HashSet seenDomains = new HashSet(); + AccessControlContext context = null; + + // We walk down the stack, adding each ProtectionDomain for each + // class in the call stack. If we reach a call to doPrivileged, + // we don't add any more stack frames. We skip the first three stack + // frames, since they comprise the calls to getStack, getContext, + // and AccessController.getContext. + for (int i = 3; i < classes.length; i++) + { + Class clazz = classes[i]; + String method = methods[i]; + + if (DEBUG) debug (">>> checking " + clazz + "." + method); + + if (DEBUG) debug (">>> loader = " + clazz.getClassLoader()); + + if (clazz.equals (AccessController.class) + && method.equals ("doPrivileged")) + { + // If there was a call to doPrivileged with a supplied context, + // return that context. + List pair = new ArrayList(2); + pair.add (Thread.currentThread()); + pair.add (classes[i-1]); + if (contexts.containsKey (pair)) + context = (AccessControlContext) contexts.get (pair); + break; + } + + ProtectionDomain domain = clazz.getProtectionDomain(); + + if (domain == null) + continue; + if (seenDomains.contains (domain)) + continue; + seenDomains.add (domain); + + // Create a static snapshot of this domain, which may change over time + // if the current policy changes. + domains.add (new ProtectionDomain (domain.getCodeSource(), + domain.getPermissions())); + } + + if (DEBUG) debug ("created domains: " + domains); + + ProtectionDomain[] result = (ProtectionDomain[]) + domains.toArray (new ProtectionDomain[domains.size()]); + + // Intersect the derived protection domain with the context supplied + // to doPrivileged. + if (context != null) + context = new AccessControlContext (result, context, + IntersectingDomainCombiner.SINGLETON); + // No context was supplied. Return the derived one. + else + context = new AccessControlContext (result); + + inGetContext.set (Boolean.FALSE); + return context; + } + + /** + * Returns a snapshot of the current call stack as a pair of arrays: + * the first an array of classes in the call stack, the second an array + * of strings containing the method names in the call stack. The two + * arrays match up, meaning that method i is declared in class + * i. The arrays are clean; it will only contain Java methods, + * and no element of the list should be null. + * + *
XXX note: this interface (VMAccessController) would possibly be + * cleaner if we had a method similar to this, but returned an array + * of java.lang.reflect.Method objects. Then, instead of having this + * much logic in this class, we put everything in AccessController, + * and simply have this single getStack method for a VM to implement. + */ + private static native Object[][] getStack(); +} Index: vm/reference/java/security/Makefile.am =================================================================== RCS file: vm/reference/java/security/Makefile.am diff -N vm/reference/java/security/Makefile.am --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ vm/reference/java/security/Makefile.am 3 Jun 2004 09:10:38 -0000 @@ -0,0 +1,5 @@ +# used by automake to generate Makefile.in + + +EXTRA_DIST = \ +VMAccessController.java Index: vm/reference/java/Makefile.am =================================================================== RCS file: /cvsroot/classpath/classpath/vm/reference/java/Makefile.am,v retrieving revision 1.2 diff -u -b -B -r1.2 Makefile.am --- vm/reference/java/Makefile.am 17 Jan 2003 16:45:28 -0000 1.2 +++ vm/reference/java/Makefile.am 3 Jun 2004 09:10:38 -0000 @@ -1,3 +1,3 @@ # used by automake to generate Makefile.in -SUBDIRS = lang io +SUBDIRS = lang io security Index: configure.ac =================================================================== RCS file: /cvsroot/classpath/classpath/configure.ac,v retrieving revision 1.29 diff -u -b -B -r1.29 configure.ac --- configure.ac 28 May 2004 10:25:30 -0000 1.29 +++ configure.ac 3 Jun 2004 09:10:38 -0000 @@ -447,6 +447,7 @@ vm/reference/java/lang/Makefile vm/reference/java/lang/reflect/Makefile vm/reference/java/io/Makefile +vm/reference/java/security/Makefile lib/Makefile lib/gen-classlist.sh]) AC_CONFIG_COMMANDS([gen-classlist],[chmod 755 lib/gen-classlist.sh])