mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			688 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			688 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Java
		
	
	
	
/* PolicyFile.java -- policy file reader
 | 
						|
   Copyright (C) 2004, 2005, 2006  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., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 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 gnu.classpath.debug.Component;
 | 
						|
import gnu.classpath.debug.SystemLogger;
 | 
						|
 | 
						|
import gnu.java.lang.CPStringBuilder;
 | 
						|
import gnu.java.security.action.GetPropertyAction;
 | 
						|
 | 
						|
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;
 | 
						|
import java.util.logging.Logger;
 | 
						|
 | 
						|
/**
 | 
						|
 * An implementation of a {@link java.security.Policy} object whose
 | 
						|
 * permissions are specified by a <em>policy file</em>.
 | 
						|
 *
 | 
						|
 * <p>The approximate syntax of policy files is:</p>
 | 
						|
 *
 | 
						|
 * <pre>
 | 
						|
 * 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;
 | 
						|
 * </pre>
 | 
						|
 *
 | 
						|
 * <p>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 <code>${property-name}</code> will be
 | 
						|
 * replaced with <code>System.getProperty("property-name")</code> in
 | 
						|
 * quoted strings.</p>
 | 
						|
 *
 | 
						|
 * <p>This class will load the following files when created or
 | 
						|
 * refreshed, in order:</p>
 | 
						|
 *
 | 
						|
 * <ol>
 | 
						|
 * <li>The file <code>${java.home}/lib/security/java.policy</code>.</li>
 | 
						|
 * <li>All URLs specified by security properties
 | 
						|
 * <code>"policy.file.<i>n</i>"</code>, for increasing <i>n</i>
 | 
						|
 * starting from 1. The sequence stops at the first undefined
 | 
						|
 * property, so you must set <code>"policy.file.1"</code> if you also
 | 
						|
 * set <code>"policy.file.2"</code>, and so on.</li>
 | 
						|
 * <li>The URL specified by the property
 | 
						|
 * <code>"java.security.policy"</code>.</li>
 | 
						|
 * </ol>
 | 
						|
 *
 | 
						|
 * @author Casey Marshall (csm@gnu.org)
 | 
						|
 * @see java.security.Policy
 | 
						|
 */
 | 
						|
public final class PolicyFile extends Policy
 | 
						|
{
 | 
						|
 | 
						|
  // Constants and fields.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  protected static final Logger logger = SystemLogger.SYSTEM;
 | 
						|
  // Added to cut redundant AccessController.doPrivileged calls
 | 
						|
  private static GetPropertyAction prop = new GetPropertyAction("file.separator");
 | 
						|
  private static final String fs = (String) AccessController.doPrivileged(prop);
 | 
						|
 | 
						|
  private static final String DEFAULT_POLICY =
 | 
						|
    (String) AccessController.doPrivileged(prop.setParameters("java.home"))
 | 
						|
    + fs + "lib" + fs + "security" + fs + "java.policy";
 | 
						|
  private static final String DEFAULT_USER_POLICY =
 | 
						|
    (String) AccessController.doPrivileged(prop.setParameters("user.home")) +
 | 
						|
    fs + ".java.policy";
 | 
						|
 | 
						|
  private final Map cs2pc;
 | 
						|
 | 
						|
  // Constructors.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  public PolicyFile()
 | 
						|
  {
 | 
						|
    cs2pc = new HashMap();
 | 
						|
    refresh();
 | 
						|
  }
 | 
						|
 | 
						|
  // Instance methods.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  public PermissionCollection getPermissions(CodeSource codeSource)
 | 
						|
  {
 | 
						|
    Permissions perms = new Permissions();
 | 
						|
    for (Iterator it = cs2pc.entrySet().iterator(); it.hasNext(); )
 | 
						|
      {
 | 
						|
        Map.Entry e = (Map.Entry) it.next();
 | 
						|
        CodeSource cs = (CodeSource) e.getKey();
 | 
						|
        if (cs.implies(codeSource))
 | 
						|
          {
 | 
						|
            logger.log (Component.POLICY, "{0} -> {1}", new Object[]
 | 
						|
              { cs, codeSource });
 | 
						|
            PermissionCollection pc = (PermissionCollection) e.getValue();
 | 
						|
            for (Enumeration ee = pc.elements(); ee.hasMoreElements(); )
 | 
						|
              {
 | 
						|
                perms.add((Permission) ee.nextElement());
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else
 | 
						|
          logger.log (Component.POLICY, "{0} !-> {1}", new Object[]
 | 
						|
            { cs, codeSource });
 | 
						|
      }
 | 
						|
    logger.log (Component.POLICY, "returning permissions {0} for {1}",
 | 
						|
                new Object[] { perms, codeSource });
 | 
						|
    return perms;
 | 
						|
  }
 | 
						|
 | 
						|
  public void refresh()
 | 
						|
  {
 | 
						|
    cs2pc.clear();
 | 
						|
    final List policyFiles = new LinkedList();
 | 
						|
    try
 | 
						|
      {
 | 
						|
        policyFiles.add (new File (DEFAULT_POLICY).toURL());
 | 
						|
        policyFiles.add (new File (DEFAULT_USER_POLICY).toURL ());
 | 
						|
 | 
						|
        AccessController.doPrivileged(
 | 
						|
          new PrivilegedExceptionAction()
 | 
						|
          {
 | 
						|
            public Object run() throws Exception
 | 
						|
            {
 | 
						|
              String allow = Security.getProperty ("policy.allowSystemProperty");
 | 
						|
              if (allow == null || Boolean.getBoolean (allow))
 | 
						|
                {
 | 
						|
                  String s = System.getProperty ("java.security.policy");
 | 
						|
                  logger.log (Component.POLICY, "java.security.policy={0}", s);
 | 
						|
                  if (s != null)
 | 
						|
                    {
 | 
						|
                      boolean only = s.startsWith ("=");
 | 
						|
                      if (only)
 | 
						|
                        s = s.substring (1);
 | 
						|
                      policyFiles.clear ();
 | 
						|
                      policyFiles.add (new URL (s));
 | 
						|
                      if (only)
 | 
						|
                        return null;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
              for (int i = 1; ; i++)
 | 
						|
                {
 | 
						|
                  String pname = "policy.url." + i;
 | 
						|
                  String s = Security.getProperty (pname);
 | 
						|
                  logger.log (Component.POLICY, "{0}={1}", new Object []
 | 
						|
                    { pname, s });
 | 
						|
                  if (s == null)
 | 
						|
                    break;
 | 
						|
                  policyFiles.add (new URL (s));
 | 
						|
                }
 | 
						|
              return null;
 | 
						|
            }
 | 
						|
          });
 | 
						|
      }
 | 
						|
    catch (PrivilegedActionException pae)
 | 
						|
      {
 | 
						|
        logger.log (Component.POLICY, "reading policy properties", pae);
 | 
						|
      }
 | 
						|
    catch (MalformedURLException mue)
 | 
						|
      {
 | 
						|
        logger.log (Component.POLICY, "setting default policies", mue);
 | 
						|
      }
 | 
						|
 | 
						|
    logger.log (Component.POLICY, "building policy from URLs {0}",
 | 
						|
                policyFiles);
 | 
						|
    for (Iterator it = policyFiles.iterator(); it.hasNext(); )
 | 
						|
      {
 | 
						|
        try
 | 
						|
          {
 | 
						|
            URL url = (URL) it.next();
 | 
						|
            parse(url);
 | 
						|
          }
 | 
						|
        catch (IOException ioe)
 | 
						|
          {
 | 
						|
            logger.log (Component.POLICY, "reading policy", ioe);
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  public String toString()
 | 
						|
  {
 | 
						|
    return super.toString() + " [ " + cs2pc.toString() + " ]";
 | 
						|
  }
 | 
						|
 | 
						|
  // Own methods.
 | 
						|
  // -------------------------------------------------------------------------
 | 
						|
 | 
						|
  private static final int STATE_BEGIN = 0;
 | 
						|
  private static final int STATE_GRANT = 1;
 | 
						|
  private static final int STATE_PERMS = 2;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Parse a policy file, incorporating the permission definitions
 | 
						|
   * described therein.
 | 
						|
   *
 | 
						|
   * @param url The URL of the policy file to read.
 | 
						|
   * @throws IOException if an I/O error occurs, or if the policy file
 | 
						|
   * cannot be parsed.
 | 
						|
   */
 | 
						|
  private void parse(final URL url) throws IOException
 | 
						|
  {
 | 
						|
    logger.log (Component.POLICY, "reading policy file from {0}", url);
 | 
						|
    final StreamTokenizer in = new StreamTokenizer(new InputStreamReader(url.openStream()));
 | 
						|
    in.resetSyntax();
 | 
						|
    in.slashSlashComments(true);
 | 
						|
    in.slashStarComments(true);
 | 
						|
    in.wordChars('A', 'Z');
 | 
						|
    in.wordChars('a', 'z');
 | 
						|
    in.wordChars('0', '9');
 | 
						|
    in.wordChars('.', '.');
 | 
						|
    in.wordChars('_', '_');
 | 
						|
    in.wordChars('$', '$');
 | 
						|
    in.whitespaceChars(' ', ' ');
 | 
						|
    in.whitespaceChars('\t', '\t');
 | 
						|
    in.whitespaceChars('\f', '\f');
 | 
						|
    in.whitespaceChars('\n', '\n');
 | 
						|
    in.whitespaceChars('\r', '\r');
 | 
						|
    in.quoteChar('\'');
 | 
						|
    in.quoteChar('"');
 | 
						|
 | 
						|
    int tok;
 | 
						|
    int state = STATE_BEGIN;
 | 
						|
    List keystores = new LinkedList();
 | 
						|
    URL currentBase = null;
 | 
						|
    List currentCerts = new LinkedList();
 | 
						|
    Permissions currentPerms = new Permissions();
 | 
						|
    while ((tok = in.nextToken()) != StreamTokenizer.TT_EOF)
 | 
						|
      {
 | 
						|
        switch (tok)
 | 
						|
          {
 | 
						|
          case '{':
 | 
						|
            if (state != STATE_GRANT)
 | 
						|
              error(url, in, "spurious '{'");
 | 
						|
            state = STATE_PERMS;
 | 
						|
            tok = in.nextToken();
 | 
						|
            break;
 | 
						|
          case '}':
 | 
						|
            if (state != STATE_PERMS)
 | 
						|
              error(url, in, "spurious '}'");
 | 
						|
            state = STATE_BEGIN;
 | 
						|
            currentPerms.setReadOnly();
 | 
						|
            Certificate[] c = null;
 | 
						|
            if (!currentCerts.isEmpty())
 | 
						|
              c = (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]);
 | 
						|
            cs2pc.put(new CodeSource(currentBase, c), currentPerms);
 | 
						|
            currentCerts.clear();
 | 
						|
            currentPerms = new Permissions();
 | 
						|
            currentBase = null;
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != ';')
 | 
						|
              in.pushBack();
 | 
						|
            continue;
 | 
						|
          }
 | 
						|
        if (tok != StreamTokenizer.TT_WORD)
 | 
						|
          {
 | 
						|
            error(url, in, "expecting word token");
 | 
						|
          }
 | 
						|
 | 
						|
        // keystore "<keystore-path>" [',' "<keystore-type>"] ';'
 | 
						|
        if (in.sval.equalsIgnoreCase("keystore"))
 | 
						|
          {
 | 
						|
            String alg = KeyStore.getDefaultType();
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != '"' && tok != '\'')
 | 
						|
              error(url, in, "expecting key store URL");
 | 
						|
            String store = in.sval;
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok == ',')
 | 
						|
              {
 | 
						|
                tok = in.nextToken();
 | 
						|
                if (tok != '"' && tok != '\'')
 | 
						|
                  error(url, in, "expecting key store type");
 | 
						|
                alg = in.sval;
 | 
						|
                tok = in.nextToken();
 | 
						|
              }
 | 
						|
            if (tok != ';')
 | 
						|
              error(url, in, "expecting semicolon");
 | 
						|
            try
 | 
						|
              {
 | 
						|
                KeyStore keystore = KeyStore.getInstance(alg);
 | 
						|
                keystore.load(new URL(url, store).openStream(), null);
 | 
						|
                keystores.add(keystore);
 | 
						|
              }
 | 
						|
            catch (Exception x)
 | 
						|
              {
 | 
						|
                error(url, in, x.toString());
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else if (in.sval.equalsIgnoreCase("grant"))
 | 
						|
          {
 | 
						|
            if (state != STATE_BEGIN)
 | 
						|
              error(url, in, "extraneous grant keyword");
 | 
						|
            state = STATE_GRANT;
 | 
						|
          }
 | 
						|
        else if (in.sval.equalsIgnoreCase("signedBy"))
 | 
						|
          {
 | 
						|
            if (state != STATE_GRANT && state != STATE_PERMS)
 | 
						|
              error(url, in, "spurious 'signedBy'");
 | 
						|
            if (keystores.isEmpty())
 | 
						|
              error(url, in, "'signedBy' with no keystores");
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != '"' && tok != '\'')
 | 
						|
              error(url, in, "expecting signedBy name");
 | 
						|
            StringTokenizer st = new StringTokenizer(in.sval, ",");
 | 
						|
            while (st.hasMoreTokens())
 | 
						|
              {
 | 
						|
                String alias = st.nextToken();
 | 
						|
                for (Iterator it = keystores.iterator(); it.hasNext(); )
 | 
						|
                  {
 | 
						|
                    KeyStore keystore = (KeyStore) it.next();
 | 
						|
                    try
 | 
						|
                      {
 | 
						|
                        if (keystore.isCertificateEntry(alias))
 | 
						|
                          currentCerts.add(keystore.getCertificate(alias));
 | 
						|
                      }
 | 
						|
                    catch (KeyStoreException kse)
 | 
						|
                      {
 | 
						|
                        error(url, in, kse.toString());
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != ',')
 | 
						|
              {
 | 
						|
                if (state != STATE_GRANT)
 | 
						|
                  error(url, in, "spurious ','");
 | 
						|
                in.pushBack();
 | 
						|
              }
 | 
						|
          }
 | 
						|
        else if (in.sval.equalsIgnoreCase("codeBase"))
 | 
						|
          {
 | 
						|
            if (state != STATE_GRANT)
 | 
						|
              error(url, in, "spurious 'codeBase'");
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != '"' && tok != '\'')
 | 
						|
              error(url, in, "expecting code base URL");
 | 
						|
            String base = expand(in.sval);
 | 
						|
            if (File.separatorChar != '/')
 | 
						|
              base = base.replace(File.separatorChar, '/');
 | 
						|
            try
 | 
						|
              {
 | 
						|
                currentBase = new URL(base);
 | 
						|
              }
 | 
						|
            catch (MalformedURLException mue)
 | 
						|
              {
 | 
						|
                error(url, in, mue.toString());
 | 
						|
              }
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != ',')
 | 
						|
              in.pushBack();
 | 
						|
          }
 | 
						|
        else if (in.sval.equalsIgnoreCase("principal"))
 | 
						|
          {
 | 
						|
            if (state != STATE_GRANT)
 | 
						|
              error(url, in, "spurious 'principal'");
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok == StreamTokenizer.TT_WORD)
 | 
						|
              {
 | 
						|
                tok = in.nextToken();
 | 
						|
                if (tok != '"' && tok != '\'')
 | 
						|
                  error(url, in, "expecting principal name");
 | 
						|
                String name = in.sval;
 | 
						|
                Principal p = null;
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    Class pclass = Class.forName(in.sval);
 | 
						|
                    Constructor c =
 | 
						|
                      pclass.getConstructor(new Class[] { String.class });
 | 
						|
                    p = (Principal) c.newInstance(new Object[] { name });
 | 
						|
                  }
 | 
						|
                catch (Exception x)
 | 
						|
                  {
 | 
						|
                    error(url, in, x.toString());
 | 
						|
                  }
 | 
						|
                for (Iterator it = keystores.iterator(); it.hasNext(); )
 | 
						|
                  {
 | 
						|
                    KeyStore ks = (KeyStore) it.next();
 | 
						|
                    try
 | 
						|
                      {
 | 
						|
                        for (Enumeration e = ks.aliases(); e.hasMoreElements(); )
 | 
						|
                          {
 | 
						|
                            String alias = (String) e.nextElement();
 | 
						|
                            if (ks.isCertificateEntry(alias))
 | 
						|
                              {
 | 
						|
                                Certificate cert = ks.getCertificate(alias);
 | 
						|
                                if (!(cert instanceof X509Certificate))
 | 
						|
                                  continue;
 | 
						|
                                if (p.equals(((X509Certificate) cert).getSubjectDN()) ||
 | 
						|
                                    p.equals(((X509Certificate) cert).getSubjectX500Principal()))
 | 
						|
                                  currentCerts.add(cert);
 | 
						|
                              }
 | 
						|
                          }
 | 
						|
                      }
 | 
						|
                    catch (KeyStoreException kse)
 | 
						|
                      {
 | 
						|
                        error(url, in, kse.toString());
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            else if (tok == '"' || tok == '\'')
 | 
						|
              {
 | 
						|
                String alias = in.sval;
 | 
						|
                for (Iterator it = keystores.iterator(); it.hasNext(); )
 | 
						|
                  {
 | 
						|
                    KeyStore ks = (KeyStore) it.next();
 | 
						|
                    try
 | 
						|
                      {
 | 
						|
                        if (ks.isCertificateEntry(alias))
 | 
						|
                          currentCerts.add(ks.getCertificate(alias));
 | 
						|
                      }
 | 
						|
                    catch (KeyStoreException kse)
 | 
						|
                      {
 | 
						|
                        error(url, in, kse.toString());
 | 
						|
                      }
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            else
 | 
						|
              error(url, in, "expecting principal");
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != ',')
 | 
						|
              in.pushBack();
 | 
						|
          }
 | 
						|
        else if (in.sval.equalsIgnoreCase("permission"))
 | 
						|
          {
 | 
						|
            if (state != STATE_PERMS)
 | 
						|
              error(url, in, "spurious 'permission'");
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != StreamTokenizer.TT_WORD)
 | 
						|
              error(url, in, "expecting permission class name");
 | 
						|
            String className = in.sval;
 | 
						|
            Class clazz = null;
 | 
						|
            try
 | 
						|
              {
 | 
						|
                clazz = Class.forName(className);
 | 
						|
              }
 | 
						|
            catch (ClassNotFoundException cnfe)
 | 
						|
              {
 | 
						|
              }
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok == ';')
 | 
						|
              {
 | 
						|
                if (clazz == null)
 | 
						|
                  {
 | 
						|
                    currentPerms.add(new UnresolvedPermission(className,
 | 
						|
                      null, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
 | 
						|
                    continue;
 | 
						|
                  }
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    currentPerms.add((Permission) clazz.newInstance());
 | 
						|
                  }
 | 
						|
                catch (Exception x)
 | 
						|
                  {
 | 
						|
                    error(url, in, x.toString());
 | 
						|
                  }
 | 
						|
                continue;
 | 
						|
              }
 | 
						|
            if (tok != '"' && tok != '\'')
 | 
						|
              error(url, in, "expecting permission target");
 | 
						|
            String target = expand(in.sval);
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok == ';')
 | 
						|
              {
 | 
						|
                if (clazz == null)
 | 
						|
                  {
 | 
						|
                    currentPerms.add(new UnresolvedPermission(className,
 | 
						|
                      target, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
 | 
						|
                    continue;
 | 
						|
                  }
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    Constructor c =
 | 
						|
                      clazz.getConstructor(new Class[] { String.class });
 | 
						|
                    currentPerms.add((Permission) c.newInstance(
 | 
						|
                      new Object[] { target }));
 | 
						|
                  }
 | 
						|
                catch (Exception x)
 | 
						|
                  {
 | 
						|
                    error(url, in, x.toString());
 | 
						|
                  }
 | 
						|
                continue;
 | 
						|
              }
 | 
						|
            if (tok != ',')
 | 
						|
              error(url, in, "expecting ','");
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok == StreamTokenizer.TT_WORD)
 | 
						|
              {
 | 
						|
                if (!in.sval.equalsIgnoreCase("signedBy"))
 | 
						|
                  error(url, in, "expecting 'signedBy'");
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    Constructor c =
 | 
						|
                      clazz.getConstructor(new Class[] { String.class });
 | 
						|
                    currentPerms.add((Permission) c.newInstance(
 | 
						|
                      new Object[] { target }));
 | 
						|
                  }
 | 
						|
                catch (Exception x)
 | 
						|
                  {
 | 
						|
                    error(url, in, x.toString());
 | 
						|
                  }
 | 
						|
                in.pushBack();
 | 
						|
                continue;
 | 
						|
              }
 | 
						|
            if (tok != '"' && tok != '\'')
 | 
						|
              error(url, in, "expecting permission action");
 | 
						|
            String action = in.sval;
 | 
						|
            if (clazz == null)
 | 
						|
              {
 | 
						|
                currentPerms.add(new UnresolvedPermission(className,
 | 
						|
                  target, action, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()])));
 | 
						|
                continue;
 | 
						|
              }
 | 
						|
            else
 | 
						|
              {
 | 
						|
                try
 | 
						|
                  {
 | 
						|
                    Constructor c = clazz.getConstructor(
 | 
						|
                      new Class[] { String.class, String.class });
 | 
						|
                    currentPerms.add((Permission) c.newInstance(
 | 
						|
                      new Object[] { target, action }));
 | 
						|
                  }
 | 
						|
                catch (Exception x)
 | 
						|
                  {
 | 
						|
                    error(url, in, x.toString());
 | 
						|
                  }
 | 
						|
              }
 | 
						|
            tok = in.nextToken();
 | 
						|
            if (tok != ';' && tok != ',')
 | 
						|
              error(url, in, "expecting ';' or ','");
 | 
						|
          }
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Expand all instances of <code>"${property-name}"</code> into
 | 
						|
   * <code>System.getProperty("property-name")</code>.
 | 
						|
   */
 | 
						|
  private static String expand(final String s)
 | 
						|
  {
 | 
						|
    final CPStringBuilder result = new CPStringBuilder();
 | 
						|
    final CPStringBuilder prop = new CPStringBuilder();
 | 
						|
    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);
 | 
						|
  }
 | 
						|
}
 |