-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi,

I was looking into ways to implement the AccessController.getContext
method, and devised a way to do it without dipping into native
methods. In short, it uses the getStackTrace method of Throwable to
obtain the current stack, fetches each Class named in the stack, then
gets the ProtectionDomain for that Class.

This is a kludge, and I would not be surprised that certain conditions
cause this to fail.

At any rate, there is a bug in the AccessControlContext constructor
that references the protectionDomain array before it is created.

Patches attached. Comments?

2004-02-10  Casey Marshall <[EMAIL PROTECTED]>

        * java/security/AccessControlContext.java
        (<init>): compare entries in the `context' array.
        Use `equals', not `=='.
        (toString): new method.

2004-02-10  Casey Marshall <[EMAIL PROTECTED]>

        * java/security/AccessController.java
        (contexts): new class field.
        (defaultContext): new constant.
        (doPrivileged): put supplied contexts into `contexts'.
        (doPrivileged): likewise.
        (getContext): implemented.

        * java/lang/SecurityManager.java
        (getSecurityContext): use AccessController.getContext().
        (checkPermission): use AccessControlContext.checkPermission().
        (checkPermission): likewise.
        (checkConnect): likewise.

- -- 
Casey Marshall || [EMAIL PROTECTED]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.3 (GNU/Linux)
Comment: Processed by Mailcrypt 3.5.7 <http://mailcrypt.sourceforge.net/>

iD8DBQFAKS4PgAuWMgRGsWsRAkO5AJ9uKub/3ocBRbYyYKzgnYZZ+KSbrwCeMRDc
mmymlIQIaDZrsJ2cwA/PlBU=
=DvZ9
-----END PGP SIGNATURE-----
Index: java/security/AccessController.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/security/AccessController.java,v
retrieving revision 1.5
diff -u -w -r1.5 AccessController.java
--- java/security/AccessController.java	6 May 2002 16:19:20 -0000	1.5
+++ java/security/AccessController.java	10 Feb 2004 18:52:38 -0000
@@ -1,5 +1,5 @@
 /* AccessController.java --- Access control context and permission checker
-   Copyright (C) 2001 Free Software Foundation, Inc.
+   Copyright (C) 2001,2004 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -37,6 +37,15 @@
 
 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;
+
 /**
  * Access control context and permission checker.
  * Can check permissions in the access control context of the current thread
@@ -58,6 +67,27 @@
  */
 public final class AccessController
 {
+
+  /**
+   * A mapping between pairs (<i>thread</i>, <i>classname</i>) to access
+   * control contexts. The <i>thread</i> and <i>classname</i> are the thread
+   * and <i>classname</i> current as of the last call to doPrivileged with
+   * an AccessControlContext argument.
+   */
+  private final static Map contexts = Collections.synchronizedMap(new HashMap());
+
+  private final static AccessControlContext defaultContext;
+  static
+  {
+    CodeSource source = new CodeSource(null, null);
+    Permissions permissions = new Permissions();
+    permissions.add(new AllPermission());
+    ProtectionDomain[] domain = new ProtectionDomain[] {
+      new ProtectionDomain(source, permissions)
+    };
+    defaultContext = new AccessControlContext(domain);
+  }
+
   /**
    * This class only has static methods so there is no public contructor.
    */
@@ -115,8 +145,19 @@
   public static Object doPrivileged(PrivilegedAction action,
 				    AccessControlContext context)
   {
+    final List pair = new ArrayList(2);
+    pair.add(Thread.currentThread());
+    pair.add(action.getClass().getName());
+    contexts.put(pair, context);
+    try
+      {
     return action.run();
   }
+    finally
+      {
+        contexts.remove(pair);
+      }
+  }
 
   /**
    * Calls the <code>run()</code> method of the given action with as
@@ -170,6 +211,10 @@
 				    AccessControlContext context)
     throws PrivilegedActionException
   {
+    final List pair = new ArrayList(2);
+    pair.add(Thread.currentThread());
+    pair.add(action.getClass().getName());
+    contexts.put(pair, context);
 
     try
       {
@@ -179,6 +224,10 @@
       {
 	throw new PrivilegedActionException(e);
       }
+    finally
+      {
+        contexts.remove(pair);
+      }
   }
 
   /**
@@ -191,7 +240,61 @@
    */
   public static AccessControlContext getContext()
   {
-    // For now just return an new empty context
-    return new AccessControlContext(new ProtectionDomain[0]);
+    List domains = new LinkedList();
+    Set classes = new HashSet();
+    StackTraceElement[] stack = new Throwable().getStackTrace();
+
+    // Calls to Class.getProtectionDomain will recursively call this
+    // method, so we return a default context (one that is guaranteed
+    // to allow this class access) if we find that we are already in
+    // a call to getContext.
+    for (int i = 1; i < stack.length; i++)
+      {
+        if (stack[i].getClassName().equals(AccessController.class.getName())
+            && stack[i].getMethodName().equals("getContext"))
+          return defaultContext;
+      }
+
+    // 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 stack frame
+    // since it is the call to getContext itself.
+    for (int i = 1; i < stack.length; i++)
+      {
+        // Don't add a class twice.
+        if (classes.contains(stack[i].getClassName()))
+          continue;
+
+        classes.add(stack[i].getClassName());
+
+        if (stack[i].getClassName().equals(AccessController.class.getName())
+            && stack[i].getMethodName().equals("doPrivileged"))
+          break;
+
+        // 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(stack[i].getClassName());
+        if (contexts.containsKey(pair))
+          {
+            return (AccessControlContext) contexts.get(pair);
+          }
+
+        try
+          {
+            Class clazz = Class.forName(stack[i].getClassName());
+            ProtectionDomain domain = clazz.getProtectionDomain();
+            if (domain != null)
+              domains.add(domain);
+          }
+        catch (Exception x)
+          {
+            // XXX what to do if this fails?
+          }
+      }
+
+    return new AccessControlContext((ProtectionDomain[])
+      domains.toArray(new ProtectionDomain[domains.size()]));
   }
 }
Index: java/security/AccessControlContext.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/security/AccessControlContext.java,v
retrieving revision 1.5
diff -u -w -r1.5 AccessControlContext.java
--- java/security/AccessControlContext.java	22 Jan 2002 22:27:00 -0000	1.5
+++ java/security/AccessControlContext.java	10 Feb 2004 18:52:03 -0000
@@ -1,5 +1,5 @@
 /* AccessControlContext.java --- Access Control Context Class
-   Copyright (C) 1999 Free Software Foundation, Inc.
+   Copyright (C) 1999,2004 Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
 
@@ -37,6 +37,9 @@
 
 package java.security;
 
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
 /**
    AccessControlContext makes system resource access decsion 
    based on permission rights.  
@@ -53,7 +56,7 @@
  */
 public final class AccessControlContext
 {
-  private ProtectionDomain protectionDomain[];
+  private final ProtectionDomain protectionDomain[];
   private DomainCombiner combiner;
 
   /**
@@ -69,7 +72,7 @@
     for (i = 0, j = 0; i < count; i++)
       {
 	for (k = 0; k < i; k++)
-	  if (context[k] == protectionDomain[i])
+          if (context[k].equals(context[i]))
 	    break;
 	if (k != i)		//it means previous loop did not complete
 	  continue;
@@ -81,7 +84,7 @@
     for (i = 0, j = 0; i < count2; i++)
       {
 	for (k = 0; k < i; k++)
-	  if (context[k] == protectionDomain[i])
+          if (context[k].equals(context[i]))
 	    break;
 	if (k != i)		//it means previous loop did not complete
 	  continue;
@@ -171,5 +174,25 @@
       h ^= protectionDomain[i].hashCode();
 
     return h;
+  }
+
+  public String toString()
+  {
+    StringWriter str = new StringWriter();
+    PrintWriter out = new PrintWriter(str, false);
+    out.print (AccessControlContext.class.getName());
+    out.println (" [ domains = ");
+    for (int i = 0; i < protectionDomain.length; i++)
+      {
+        out.println(protectionDomain[i]);
+      }
+    if (combiner != null)
+      {
+        out.print("domain combiner = ");
+        out.println(combiner);
+      }
+    out.println("]");
+    out.flush();
+    return str.toString();
   }
 }
Index: java/lang/SecurityManager.java
===================================================================
RCS file: /cvsroot/classpath/classpath/java/lang/SecurityManager.java,v
retrieving revision 1.16
diff -u -w -r1.16 SecurityManager.java
--- java/lang/SecurityManager.java	6 Jan 2004 09:56:04 -0000	1.16
+++ java/lang/SecurityManager.java	10 Feb 2004 18:53:10 -0000
@@ -45,6 +45,8 @@
 import java.lang.reflect.Member;
 import java.net.InetAddress;
 import java.net.SocketPermission;
+import java.security.AccessController;
+import java.security.AccessControlContext;
 import java.security.AllPermission;
 import java.security.Permission;
 import java.security.Security;
@@ -301,8 +303,7 @@
    */
   public Object getSecurityContext()
   {
-    // XXX Should be: return AccessController.getContext();
-    return new SecurityContext(getClassContext());
+    return AccessController.getContext();
   }
 
   /**
@@ -317,8 +318,7 @@
    */
   public void checkPermission(Permission perm)
   {
-    // XXX Should be: AccessController.checkPermission(perm);
-    throw new SecurityException("Operation not allowed");
+    AccessController.checkPermission(perm);
   }
 
   /**
@@ -339,11 +339,9 @@
    */
   public void checkPermission(Permission perm, Object context)
   {
-    // XXX Should be:
-    // if (! (context instanceof AccessControlContext))
-    //   throw new SecurityException("Missing context");
-    // ((AccessControlContext) context).checkPermission(perm);
-    throw new SecurityException("Operation not allowed");
+    if (!(context instanceof AccessControlContext))
+      throw new SecurityException("Missing context");
+    ((AccessControlContext) context).checkPermission(perm);
   }
 
   /**
@@ -656,19 +654,17 @@
    * @see #getSecurityContext()
    * @see AccessControlContext#checkPermission(Permission)
    */
-  public void checkConnect(String host, int port, Object securityContext)
+  public void checkConnect(String host, int port, Object context)
   {
-    // XXX Should be:
-    // if (! (context instanceof AccessControlContext))
-    //   throw new SecurityException("Missing context");
-    // AccessControlContext ac = (AccessControlContext) context;
-    // if (port == -1)
-    //   ac.checkPermission(new SocketPermission(host, "resolve"));
-    // else
-    //   // Use the toString() hack to do the null check.
-    //   ac.checkPermission(new SocketPermission(host.toString + ":" +port,
-    //                                           "connect"));
-    throw new SecurityException("Cannot make network connections.");
+    if (! (context instanceof AccessControlContext))
+      throw new SecurityException("Missing context");
+    AccessControlContext ac = (AccessControlContext) context;
+    if (port == -1)
+      ac.checkPermission(new SocketPermission(host, "resolve"));
+    else
+      // Use the toString() hack to do the null check.
+      ac.checkPermission(new SocketPermission(host.toString() + ":" + port,
+                                              "connect"));
   }
 
   /**
_______________________________________________
Classpath mailing list
[EMAIL PROTECTED]
http://mail.gnu.org/mailman/listinfo/classpath

Reply via email to