From 8dd1d383e2e25fadd1dd993bfe5a6674de0b4ede Mon Sep 17 00:00:00 2001 From: Michael Koch Date: Wed, 24 Nov 2004 15:08:13 +0000 Subject: 2004-11-24 Michael Koch * gnu/java/security/PolicyFile.java: New file. * Makefile.am: Added gnu/java/security/PolicyFile.java. * Makefile.in: Regenerated. git-svn-id: https://gcc.gnu.org/svn/gcc/trunk@91165 138bc75d-0d04-0410-961f-82ee72b054a4 --- libjava/ChangeLog | 6 + libjava/Makefile.am | 1 + libjava/Makefile.in | 9 +- libjava/gnu/java/security/PolicyFile.java | 665 ++++++++++++++++++++++++++++++ 4 files changed, 680 insertions(+), 1 deletion(-) create mode 100644 libjava/gnu/java/security/PolicyFile.java (limited to 'libjava') diff --git a/libjava/ChangeLog b/libjava/ChangeLog index becc5f4ec1f..3b7d530006e 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,3 +1,9 @@ +2004-11-24 Michael Koch + + * gnu/java/security/PolicyFile.java: New file. + * Makefile.am: Added gnu/java/security/PolicyFile.java. + * Makefile.in: Regenerated. + 2004-11-24 Michael Koch * java/lang/Character.java, scripts/unicode-blocks.pl: diff --git a/libjava/Makefile.am b/libjava/Makefile.am index 204425b59f5..192845f2cc5 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -2770,6 +2770,7 @@ gnu/java/nio/charset/UTF_16LE.java \ gnu/java/nio/charset/UTF_8.java \ gnu/java/security/Engine.java \ gnu/java/security/OID.java \ +gnu/java/security/PolicyFile.java \ gnu/java/security/action/GetPropertyAction.java \ gnu/java/security/action/GetSecurityPropertyAction.java \ gnu/java/security/action/SetAccessibleAction.java \ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index fbb42ae13f7..31032fc6f02 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -793,7 +793,7 @@ am__libgcj_la_SOURCES_DIST = prims.cc jni.cc exception.cc resolve.cc \ gnu/java/nio/charset/UTF_16Encoder.java \ gnu/java/nio/charset/UTF_16LE.java \ gnu/java/nio/charset/UTF_8.java gnu/java/security/Engine.java \ - gnu/java/security/OID.java \ + gnu/java/security/OID.java gnu/java/security/PolicyFile.java \ gnu/java/security/action/GetPropertyAction.java \ gnu/java/security/action/GetSecurityPropertyAction.java \ gnu/java/security/action/SetAccessibleAction.java \ @@ -3776,6 +3776,7 @@ am__objects_14 = $(am__objects_9) gnu/classpath/ServiceFactory.lo \ gnu/java/nio/charset/UTF_16Encoder.lo \ gnu/java/nio/charset/UTF_16LE.lo gnu/java/nio/charset/UTF_8.lo \ gnu/java/security/Engine.lo gnu/java/security/OID.lo \ + gnu/java/security/PolicyFile.lo \ gnu/java/security/action/GetPropertyAction.lo \ gnu/java/security/action/GetSecurityPropertyAction.lo \ gnu/java/security/action/SetAccessibleAction.lo \ @@ -6639,6 +6640,7 @@ gnu/java/nio/charset/UTF_16LE.java \ gnu/java/nio/charset/UTF_8.java \ gnu/java/security/Engine.java \ gnu/java/security/OID.java \ +gnu/java/security/PolicyFile.java \ gnu/java/security/action/GetPropertyAction.java \ gnu/java/security/action/GetSecurityPropertyAction.java \ gnu/java/security/action/SetAccessibleAction.java \ @@ -9475,6 +9477,8 @@ gnu/java/security/Engine.lo: gnu/java/security/$(am__dirstamp) \ gnu/java/security/$(DEPDIR)/$(am__dirstamp) gnu/java/security/OID.lo: gnu/java/security/$(am__dirstamp) \ gnu/java/security/$(DEPDIR)/$(am__dirstamp) +gnu/java/security/PolicyFile.lo: gnu/java/security/$(am__dirstamp) \ + gnu/java/security/$(DEPDIR)/$(am__dirstamp) gnu/java/security/action/$(am__dirstamp): @$(mkdir_p) gnu/java/security/action @: > gnu/java/security/action/$(am__dirstamp) @@ -15271,6 +15275,8 @@ mostlyclean-compile: -rm -f gnu/java/security/Engine.lo -rm -f gnu/java/security/OID.$(OBJEXT) -rm -f gnu/java/security/OID.lo + -rm -f gnu/java/security/PolicyFile.$(OBJEXT) + -rm -f gnu/java/security/PolicyFile.lo -rm -f gnu/java/security/action/GetPropertyAction.$(OBJEXT) -rm -f gnu/java/security/action/GetPropertyAction.lo -rm -f gnu/java/security/action/GetSecurityPropertyAction.$(OBJEXT) @@ -19921,6 +19927,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/rmi/server/$(DEPDIR)/UnicastServerRef.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/$(DEPDIR)/Engine.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/$(DEPDIR)/OID.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/$(DEPDIR)/PolicyFile.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/action/$(DEPDIR)/GetPropertyAction.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/action/$(DEPDIR)/GetSecurityPropertyAction.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@gnu/java/security/action/$(DEPDIR)/SetAccessibleAction.Plo@am__quote@ diff --git a/libjava/gnu/java/security/PolicyFile.java b/libjava/gnu/java/security/PolicyFile.java new file mode 100644 index 00000000000..d5c14dc7a17 --- /dev/null +++ b/libjava/gnu/java/security/PolicyFile.java @@ -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 {@link 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:

+ * + *
    + *
  1. The file ${java.home}/lib/security/java.policy.
  2. + *
  3. All URLs specified by security properties + * "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.
  4. + *
  5. The URL specified by the property + * "java.security.policy".
  6. + *
+ * + * @author Casey Marshall (csm@gnu.org) + * @see java.security.Policy + */ +public final class PolicyFile extends Policy +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + private static final boolean DEBUG = true; + private static void debug(String msg) + { + System.err.print(">> PolicyFile: "); + System.err.println(msg); + } + + private static void debug(Throwable t) + { + System.err.println(">> PolicyFile"); + t.printStackTrace(System.err); + } + + private static final String DEFAULT_POLICY = System.getProperty("java.home") + + System.getProperty("file.separator") + "lib" + + System.getProperty("file.separator") + "security" + + System.getProperty("file.separator") + "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)) + { + if (DEBUG) debug(cs+" -> "+codeSource); + PermissionCollection pc = (PermissionCollection) e.getValue(); + for (Enumeration ee = pc.elements(); ee.hasMoreElements(); ) + { + perms.add((Permission) ee.nextElement()); + } + } + else + if (DEBUG) debug(cs+" !-> "+codeSource); + } + if (DEBUG) debug ("returning permissions " + perms + " for " + codeSource); + return perms; + } + + public void refresh() + { + cs2pc.clear(); + List policyFiles = new LinkedList(); + try + { + policyFiles.add(new File(DEFAULT_POLICY).toURL()); + if (DEBUG) debug ("defualt policy is " + DEFAULT_POLICY); + policyFiles.addAll((List) AccessController.doPrivileged( + new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + LinkedList l = new LinkedList(); + for (int i = 1; ; i++) + { + String s = Security.getProperty("policy.file."+i); + if (DEBUG) debug("policy.file."+i+"="+s); + if (s == null) + break; + l.add(new URL(s)); + } + String s = System.getProperty("java.security.policy"); + if (DEBUG) debug("java.security.policy="+s); + if (s != null) + l.add(new URL(s)); + return l; + } + })); + } + catch (PrivilegedActionException pae) + { + if (DEBUG) debug(pae); + } + catch (MalformedURLException mue) + { + if (DEBUG) debug(mue); + } + for (Iterator it = policyFiles.iterator(); it.hasNext(); ) + { + try + { + URL url = (URL) it.next(); + parse(url); + } + catch (IOException ioe) + { + if (DEBUG) debug(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 + { + if (DEBUG) debug ("reading policy file from " + 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 "" [',' ""] ';' + 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[0]))); + 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[0]))); + 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[0]))); + 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 "${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); + } +} -- cgit v1.2.3