--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/src/share/classes/com/sun/security/auth/PolicyParser.java Sat Dec 01 00:00:00 2007 +0000
@@ -0,0 +1,962 @@
+/*
+ * Copyright 1998-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation. Sun designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Sun in the LICENSE file that accompanied this code.
+ *
+ * This code 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
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
+ * CA 95054 USA or visit www.sun.com if you need additional information or
+ * have any questions.
+ */
+
+package com.sun.security.auth;
+
+import java.io.*;
+import java.lang.RuntimePermission;
+import java.net.MalformedURLException;
+import java.net.SocketPermission;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.LinkedList;
+import java.util.ListIterator;
+import java.util.Vector;
+import java.util.StringTokenizer;
+import java.security.GeneralSecurityException;
+import sun.security.util.PropertyExpander;
+
+/**
+ * The policy for a Java runtime (specifying
+ * which permissions are available for code from various principals)
+ * is represented as a separate
+ * persistent configuration. The configuration may be stored as a
+ * flat ASCII file, as a serialized binary file of
+ * the Policy class, or as a database. <p>
+ *
+ * <p>The Java runtime creates one global Policy object, which is used to
+ * represent the static policy configuration file. It is consulted by
+ * a ProtectionDomain when the protection domain initializes its set of
+ * permissions. <p>
+ *
+ * <p>The Policy <code>init</code> method parses the policy
+ * configuration file, and then
+ * populates the Policy object. The Policy object is agnostic in that
+ * it is not involved in making policy decisions. It is merely the
+ * Java runtime representation of the persistent policy configuration
+ * file. <p>
+ *
+ * <p>When a protection domain needs to initialize its set of
+ * permissions, it executes code such as the following
+ * to ask the global Policy object to populate a
+ * Permissions object with the appropriate permissions:
+ * <pre>
+ * policy = Policy.getPolicy();
+ * Permissions perms = policy.getPermissions(MyCodeSource)
+ * </pre>
+ *
+ * <p>The protection domain passes in a CodeSource
+ * object, which encapsulates its codebase (URL) and public key attributes.
+ * The Policy object evaluates the global policy in light of who the
+ * principal is and returns an appropriate Permissions object.
+ *
+ * @deprecated As of JDK 1.4, replaced by
+ * {@link sun.security.provider.PolicyParser}.
+ * This class is entirely deprecated.
+ *
+ * @author Roland Schemers
+ *
+ * @since 1.2
+ */
+@Deprecated
+class PolicyParser {
+
+ private static final java.util.ResourceBundle rb =
+ java.security.AccessController.doPrivileged
+ (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
+ public java.util.ResourceBundle run() {
+ return (java.util.ResourceBundle.getBundle
+ ("sun.security.util.AuthResources"));
+ }
+ });
+
+ private Vector<GrantEntry> grantEntries;
+
+ // Convenience variables for parsing
+ private static final sun.security.util.Debug debug =
+ sun.security.util.Debug.getInstance("parser", "\t[Auth Policy Parser]");
+ private StreamTokenizer st;
+ private int lookahead;
+ private int linenum;
+ private boolean expandProp = false;
+ private String keyStoreUrlString = null; // unexpanded
+ private String keyStoreType = null;
+
+ private String expand(String value)
+ throws PropertyExpander.ExpandException
+ {
+ if (expandProp)
+ return PropertyExpander.expand(value);
+ else
+ return value;
+ }
+ /**
+ * Creates a PolicyParser object.
+ */
+
+ public PolicyParser() {
+ grantEntries = new Vector<GrantEntry>();
+ }
+
+
+ public PolicyParser(boolean expandProp) {
+ this();
+ this.expandProp = expandProp;
+ }
+
+ /**
+ * Reads a policy configuration into the Policy object using a
+ * Reader object. <p>
+ *
+ * @param policy the policy Reader object.
+ *
+ * @exception ParsingException if the policy configuration contains
+ * a syntax error.
+ *
+ * @exception IOException if an error occurs while reading the policy
+ * configuration.
+ */
+
+ public void read(Reader policy)
+ throws ParsingException, IOException
+ {
+ if (!(policy instanceof BufferedReader)) {
+ policy = new BufferedReader(policy);
+ }
+
+ /**
+ * Configure the stream tokenizer:
+ * Recognize strings between "..."
+ * Don't convert words to lowercase
+ * Recognize both C-style and C++-style comments
+ * Treat end-of-line as white space, not as a token
+ */
+ st = new StreamTokenizer(policy);
+
+ st.resetSyntax();
+ st.wordChars('a', 'z');
+ st.wordChars('A', 'Z');
+ st.wordChars('.', '.');
+ st.wordChars('0', '9');
+ st.wordChars('_', '_');
+ st.wordChars('$', '$');
+ st.wordChars(128 + 32, 255);
+ st.whitespaceChars(0, ' ');
+ st.commentChar('/');
+ st.quoteChar('\'');
+ st.quoteChar('"');
+ st.lowerCaseMode(false);
+ st.ordinaryChar('/');
+ st.slashSlashComments(true);
+ st.slashStarComments(true);
+
+ /**
+ * The main parsing loop. The loop is executed once
+ * for each entry in the config file. The entries
+ * are delimited by semicolons. Once we've read in
+ * the information for an entry, go ahead and try to
+ * add it to the policy vector.
+ *
+ */
+
+ lookahead = st.nextToken();
+ while (lookahead != StreamTokenizer.TT_EOF) {
+ if (peek("grant")) {
+ GrantEntry ge = parseGrantEntry();
+ // could be null if we couldn't expand a property
+ if (ge != null)
+ add(ge);
+ } else if (peek("keystore") && keyStoreUrlString==null) {
+ // only one keystore entry per policy file, others will be
+ // ignored
+ parseKeyStoreEntry();
+ } else {
+ // error?
+ }
+ match(";");
+ }
+ }
+
+ public void add(GrantEntry ge)
+ {
+ grantEntries.addElement(ge);
+ }
+
+ public void replace(GrantEntry origGe, GrantEntry newGe)
+ {
+ grantEntries.setElementAt(newGe, grantEntries.indexOf(origGe));
+ }
+
+ public boolean remove(GrantEntry ge)
+ {
+ return grantEntries.removeElement(ge);
+ }
+
+ /**
+ * Returns the (possibly expanded) keystore location, or null if the
+ * expansion fails.
+ */
+ public String getKeyStoreUrl() {
+ try {
+ if (keyStoreUrlString!=null && keyStoreUrlString.length()!=0) {
+ return expand(keyStoreUrlString).replace(File.separatorChar,
+ '/');
+ }
+ } catch (PropertyExpander.ExpandException peee) {
+ return null;
+ }
+ return null;
+ }
+
+ public void setKeyStoreUrl(String url) {
+ keyStoreUrlString = url;
+ }
+
+ public String getKeyStoreType() {
+ return keyStoreType;
+ }
+
+ public void setKeyStoreType(String type) {
+ keyStoreType = type;
+ }
+
+ /**
+ * Enumerate all the entries in the global policy object.
+ * This method is used by policy admin tools. The tools
+ * should use the Enumeration methods on the returned object
+ * to fetch the elements sequentially.
+ */
+ public Enumeration<GrantEntry> grantElements(){
+ return grantEntries.elements();
+ }
+
+ /**
+ * write out the policy
+ */
+
+ public void write(Writer policy)
+ {
+ PrintWriter out = new PrintWriter(new BufferedWriter(policy));
+
+ Enumeration<GrantEntry> enum_ = grantElements();
+
+ out.println("/* AUTOMATICALLY GENERATED ON "+
+ (new java.util.Date()) + "*/");
+ out.println("/* DO NOT EDIT */");
+ out.println();
+
+ // write the (unexpanded) keystore entry as the first entry of the
+ // policy file
+ if (keyStoreUrlString != null) {
+ writeKeyStoreEntry(out);
+ }
+
+ // write "grant" entries
+ while (enum_.hasMoreElements()) {
+ GrantEntry ge = enum_.nextElement();
+ ge.write(out);
+ out.println();
+ }
+ out.flush();
+ }
+
+ /**
+ * parses a keystore entry
+ */
+ private void parseKeyStoreEntry() throws ParsingException, IOException {
+ match("keystore");
+ keyStoreUrlString = match("quoted string");
+
+ // parse keystore type
+ if (!peek(",")) {
+ return; // default type
+ }
+ match(",");
+
+ if (peek("\"")) {
+ keyStoreType = match("quoted string");
+ } else {
+ throw new ParsingException(st.lineno(),
+ rb.getString("expected keystore type"));
+ }
+ }
+
+ /**
+ * writes the (unexpanded) keystore entry
+ */
+ private void writeKeyStoreEntry(PrintWriter out) {
+ out.print("keystore \"");
+ out.print(keyStoreUrlString);
+ out.print('"');
+ if (keyStoreType != null && keyStoreType.length() > 0)
+ out.print(", \"" + keyStoreType + "\"");
+ out.println(";");
+ out.println();
+ }
+
+ /**
+ * parse a Grant entry
+ */
+ private GrantEntry parseGrantEntry()
+ throws ParsingException, IOException
+ {
+ GrantEntry e = new GrantEntry();
+ LinkedList<PrincipalEntry> principals = null;
+ boolean ignoreEntry = false;
+
+ match("grant");
+
+ while(!peek("{")) {
+
+ if (peekAndMatch("Codebase")) {
+ e.codeBase = match("quoted string");
+ peekAndMatch(",");
+ } else if (peekAndMatch("SignedBy")) {
+ e.signedBy = match("quoted string");
+ peekAndMatch(",");
+ } else if (peekAndMatch("Principal")) {
+ if (principals == null) {
+ principals = new LinkedList<PrincipalEntry>();
+ }
+
+ // check for principalClass wildcard
+ String principalClass;
+ if (peek("*")) {
+ match("*");
+ principalClass = PrincipalEntry.WILDCARD_CLASS;
+ } else {
+ principalClass = match("principal type");
+ }
+
+ // check for principalName wildcard
+ String principalName;
+ if (peek("*")) {
+ match("*");
+ principalName = PrincipalEntry.WILDCARD_NAME;
+ } else {
+ principalName = match("quoted string");
+ }
+
+ // disallow WILDCARD_CLASS && actual name
+ if (principalClass.equals(PrincipalEntry.WILDCARD_CLASS) &&
+ !principalName.equals(PrincipalEntry.WILDCARD_NAME)) {
+ if (debug != null)
+ debug.println("disallowing principal that has " +
+ "WILDCARD class but no WILDCARD name");
+ throw new ParsingException
+ (st.lineno(),
+ rb.getString("can not specify Principal with a ") +
+ rb.getString("wildcard class without a wildcard name"));
+ }
+
+ try {
+ principalName = expand(principalName);
+ principals.add
+ (new PrincipalEntry(principalClass, principalName));
+ } catch (PropertyExpander.ExpandException peee) {
+ // ignore the entire policy entry
+ // but continue parsing all the info
+ // so we can get to the next entry
+ if (debug != null)
+ debug.println("principal name expansion failed: " +
+ principalName);
+ ignoreEntry = true;
+ }
+ peekAndMatch(",");
+ } else {
+ throw new
+ ParsingException(st.lineno(),
+ rb.getString("expected codeBase or SignedBy"));
+ }
+ }
+
+ // disallow non principal-based grant entries
+ if (principals == null) {
+ throw new ParsingException
+ (st.lineno(),
+ rb.getString("only Principal-based grant entries permitted"));
+ }
+
+ e.principals = principals;
+ match("{");
+
+ while(!peek("}")) {
+ if (peek("Permission")) {
+ try {
+ PermissionEntry pe = parsePermissionEntry();
+ e.add(pe);
+ } catch (PropertyExpander.ExpandException peee) {
+ // ignore. The add never happened
+ skipEntry(); // BugId 4219343
+ }
+ match(";");
+ } else {
+ throw new
+ ParsingException(st.lineno(),
+ rb.getString("expected permission entry"));
+ }
+ }
+ match("}");
+
+ try {
+ if (e.codeBase != null)
+ e.codeBase = expand(e.codeBase).replace(File.separatorChar, '/');
+ e.signedBy = expand(e.signedBy);
+ } catch (PropertyExpander.ExpandException peee) {
+ return null;
+ }
+
+ return (ignoreEntry == true) ? null : e;
+ }
+
+ /**
+ * parse a Permission entry
+ */
+ private PermissionEntry parsePermissionEntry()
+ throws ParsingException, IOException, PropertyExpander.ExpandException
+ {
+ PermissionEntry e = new PermissionEntry();
+
+ // Permission
+ match("Permission");
+ e.permission = match("permission type");
+
+ if (peek("\"")) {
+ // Permission name
+ e.name = expand(match("quoted string"));
+ }
+
+ if (!peek(",")) {
+ return e;
+ }
+ match(",");
+
+ if (peek("\"")) {
+ e.action = expand(match("quoted string"));
+ if (!peek(",")) {
+ return e;
+ }
+ match(",");
+ }
+
+ if (peekAndMatch("SignedBy")) {
+ e.signedBy = expand(match("quoted string"));
+ }
+ return e;
+ }
+
+ private boolean peekAndMatch(String expect)
+ throws ParsingException, IOException
+ {
+ if (peek(expect)) {
+ match(expect);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ private boolean peek(String expect) {
+ boolean found = false;
+
+ switch (lookahead) {
+
+ case StreamTokenizer.TT_WORD:
+ if (expect.equalsIgnoreCase(st.sval))
+ found = true;
+ break;
+ case ',':
+ if (expect.equalsIgnoreCase(","))
+ found = true;
+ break;
+ case '{':
+ if (expect.equalsIgnoreCase("{"))
+ found = true;
+ break;
+ case '}':
+ if (expect.equalsIgnoreCase("}"))
+ found = true;
+ break;
+ case '"':
+ if (expect.equalsIgnoreCase("\""))
+ found = true;
+ break;
+ case '*':
+ if (expect.equalsIgnoreCase("*"))
+ found = true;
+ break;
+ default:
+
+ }
+ return found;
+ }
+
+ private String match(String expect)
+ throws ParsingException, IOException
+ {
+ String value = null;
+
+ switch (lookahead) {
+ case StreamTokenizer.TT_NUMBER:
+ throw new ParsingException(st.lineno(), expect,
+ rb.getString("number ") +
+ String.valueOf(st.nval));
+ case StreamTokenizer.TT_EOF:
+ throw new ParsingException
+ (rb.getString("expected ") + expect +
+ rb.getString(", read end of file"));
+ case StreamTokenizer.TT_WORD:
+ if (expect.equalsIgnoreCase(st.sval)) {
+ lookahead = st.nextToken();
+ } else if (expect.equalsIgnoreCase("permission type")) {
+ value = st.sval;
+ lookahead = st.nextToken();
+ } else if (expect.equalsIgnoreCase("principal type")) {
+ value = st.sval;
+ lookahead = st.nextToken();
+ } else {
+ throw new ParsingException(st.lineno(), expect, st.sval);
+ }
+ break;
+ case '"':
+ if (expect.equalsIgnoreCase("quoted string")) {
+ value = st.sval;
+ lookahead = st.nextToken();
+ } else if (expect.equalsIgnoreCase("permission type")) {
+ value = st.sval;
+ lookahead = st.nextToken();
+ } else if (expect.equalsIgnoreCase("principal type")) {
+ value = st.sval;
+ lookahead = st.nextToken();
+ } else {
+ throw new ParsingException(st.lineno(), expect, st.sval);
+ }
+ break;
+ case ',':
+ if (expect.equalsIgnoreCase(","))
+ lookahead = st.nextToken();
+ else
+ throw new ParsingException(st.lineno(), expect, ",");
+ break;
+ case '{':
+ if (expect.equalsIgnoreCase("{"))
+ lookahead = st.nextToken();
+ else
+ throw new ParsingException(st.lineno(), expect, "{");
+ break;
+ case '}':
+ if (expect.equalsIgnoreCase("}"))
+ lookahead = st.nextToken();
+ else
+ throw new ParsingException(st.lineno(), expect, "}");
+ break;
+ case ';':
+ if (expect.equalsIgnoreCase(";"))
+ lookahead = st.nextToken();
+ else
+ throw new ParsingException(st.lineno(), expect, ";");
+ break;
+ case '*':
+ if (expect.equalsIgnoreCase("*"))
+ lookahead = st.nextToken();
+ else
+ throw new ParsingException(st.lineno(), expect, "*");
+ break;
+ default:
+ throw new ParsingException(st.lineno(), expect,
+ new String(new char[] {(char)lookahead}));
+ }
+ return value;
+ }
+
+ /**
+ * skip all tokens for this entry leaving the delimiter ";"
+ * in the stream.
+ */
+ private void skipEntry()
+ throws ParsingException, IOException
+ {
+ while(lookahead != ';') {
+ switch (lookahead) {
+ case StreamTokenizer.TT_NUMBER:
+ throw new ParsingException(st.lineno(), ";",
+ rb.getString("number ") +
+ String.valueOf(st.nval));
+ case StreamTokenizer.TT_EOF:
+ throw new ParsingException
+ (rb.getString("expected ';', read end of file"));
+ default:
+ lookahead = st.nextToken();
+ }
+ }
+ }
+
+ /**
+ * Each grant entry in the policy configuration file is
+ * represented by a
+ * GrantEntry object. <p>
+ *
+ * <p>
+ * For example, the entry
+ * <pre>
+ * grant signedBy "Duke" {
+ * permission java.io.FilePermission "/tmp", "read,write";
+ * };
+ *
+ * </pre>
+ * is represented internally
+ * <pre>
+ *
+ * pe = new PermissionEntry("java.io.FilePermission",
+ * "/tmp", "read,write");
+ *
+ * ge = new GrantEntry("Duke", null);
+ *
+ * ge.add(pe);
+ *
+ * </pre>
+ *
+ * @author Roland Schemers
+ *
+ * version 1.19, 05/21/98
+ */
+
+ static class GrantEntry {
+
+ public String signedBy;
+ public String codeBase;
+ public LinkedList<PrincipalEntry> principals;
+ public Vector<PermissionEntry> permissionEntries;
+
+ public GrantEntry() {
+ permissionEntries = new Vector<PermissionEntry>();
+ }
+
+ public GrantEntry(String signedBy, String codeBase) {
+ this.codeBase = codeBase;
+ this.signedBy = signedBy;
+ permissionEntries = new Vector<PermissionEntry>();
+ }
+
+ public void add(PermissionEntry pe)
+ {
+ permissionEntries.addElement(pe);
+ }
+
+ public boolean remove(PermissionEntry pe)
+ {
+ return permissionEntries.removeElement(pe);
+ }
+
+ public boolean contains(PermissionEntry pe)
+ {
+ return permissionEntries.contains(pe);
+ }
+
+ /**
+ * Enumerate all the permission entries in this GrantEntry.
+ */
+ public Enumeration<PermissionEntry> permissionElements(){
+ return permissionEntries.elements();
+ }
+
+
+ public void write(PrintWriter out) {
+ out.print("grant");
+ if (signedBy != null) {
+ out.print(" signedBy \"");
+ out.print(signedBy);
+ out.print('"');
+ if (codeBase != null)
+ out.print(", ");
+ }
+ if (codeBase != null) {
+ out.print(" codeBase \"");
+ out.print(codeBase);
+ out.print('"');
+ if (principals != null && principals.size() > 0)
+ out.print(",\n");
+ }
+ if (principals != null && principals.size() > 0) {
+ ListIterator<PrincipalEntry> pli = principals.listIterator();
+ while (pli.hasNext()) {
+ out.print("\tPrincipal ");
+ PrincipalEntry pe = pli.next();
+ out.print(pe.principalClass +
+ " \"" + pe.principalName + "\"");
+ if (pli.hasNext())
+ out.print(",\n");
+ }
+ }
+ out.println(" {");
+ Enumeration<PermissionEntry> enum_ = permissionEntries.elements();
+ while (enum_.hasMoreElements()) {
+ PermissionEntry pe = enum_.nextElement();
+ out.write(" ");
+ pe.write(out);
+ }
+ out.println("};");
+ }
+
+ }
+
+ /**
+ * Principal info (class and name) in a grant entry
+ */
+ static class PrincipalEntry {
+
+ static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS";
+ static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME";
+
+ String principalClass;
+ String principalName;
+
+ /**
+ * A PrincipalEntry consists of the <code>Principal</code>
+ * class and <code>Principal</code> name.
+ *
+ * <p>
+ *
+ * @param principalClass the <code>Principal</code> class. <p>
+ *
+ * @param principalName the <code>Principal</code> name. <p>
+ */
+ public PrincipalEntry(String principalClass, String principalName) {
+ if (principalClass == null || principalName == null)
+ throw new NullPointerException
+ ("null principalClass or principalName");
+ this.principalClass = principalClass;
+ this.principalName = principalName;
+ }
+
+ /**
+ * Test for equality between the specified object and this object.
+ * Two PrincipalEntries are equal if their PrincipalClass and
+ * PrincipalName values are equal.
+ *
+ * <p>
+ *
+ * @param obj the object to test for equality with this object.
+ *
+ * @return true if the objects are equal, false otherwise.
+ */
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+
+ if (!(obj instanceof PrincipalEntry))
+ return false;
+
+ PrincipalEntry that = (PrincipalEntry)obj;
+ if (this.principalClass.equals(that.principalClass) &&
+ this.principalName.equals(that.principalName)) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Return a hashcode for this <code>PrincipalEntry</code>.
+ *
+ * <p>
+ *
+ * @return a hashcode for this <code>PrincipalEntry</code>.
+ */
+ public int hashCode() {
+ return principalClass.hashCode();
+ }
+ }
+
+ /**
+ * Each permission entry in the policy configuration file is
+ * represented by a
+ * PermissionEntry object. <p>
+ *
+ * <p>
+ * For example, the entry
+ * <pre>
+ * permission java.io.FilePermission "/tmp", "read,write";
+ * </pre>
+ * is represented internally
+ * <pre>
+ *
+ * pe = new PermissionEntry("java.io.FilePermission",
+ * "/tmp", "read,write");
+ * </pre>
+ *
+ * @author Roland Schemers
+ *
+ * version 1.19, 05/21/98
+ */
+
+ static class PermissionEntry {
+
+ public String permission;
+ public String name;
+ public String action;
+ public String signedBy;
+
+ public PermissionEntry() {
+ }
+
+ public PermissionEntry(String permission,
+ String name,
+ String action) {
+ this.permission = permission;
+ this.name = name;
+ this.action = action;
+ }
+
+ /**
+ * Calculates a hash code value for the object. Objects
+ * which are equal will also have the same hashcode.
+ */
+ public int hashCode() {
+ int retval = permission.hashCode();
+ if (name != null) retval ^= name.hashCode();
+ if (action != null) retval ^= action.hashCode();
+ return retval;
+ }
+
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+
+ if (! (obj instanceof PermissionEntry))
+ return false;
+
+ PermissionEntry that = (PermissionEntry) obj;
+
+ if (this.permission == null) {
+ if (that.permission != null) return false;
+ } else {
+ if (!this.permission.equals(that.permission)) return false;
+ }
+
+ if (this.name == null) {
+ if (that.name != null) return false;
+ } else {
+ if (!this.name.equals(that.name)) return false;
+ }
+
+ if (this.action == null) {
+ if (that.action != null) return false;
+ } else {
+ if (!this.action.equals(that.action)) return false;
+ }
+
+ if (this.signedBy == null) {
+ if (that.signedBy != null) return false;
+ } else {
+ if (!this.signedBy.equals(that.signedBy)) return false;
+ }
+
+ // everything matched -- the 2 objects are equal
+ return true;
+ }
+
+ public void write(PrintWriter out) {
+ out.print("permission ");
+ out.print(permission);
+ if (name != null) {
+ out.print(" \"");
+
+ // have to add escape chars for quotes
+ if (name.indexOf("\"") != -1) {
+ int numQuotes = 0;
+ char[] chars = name.toCharArray();
+
+ // count the number of quote chars
+ for (int i = 0; i < chars.length; i++) {
+ if (chars[i] == '"')
+ numQuotes++;
+ }
+
+ // now, add an escape char before each quote
+ char[] newChars = new char[chars.length + numQuotes];
+ for (int i = 0, j = 0; i < chars.length; i++) {
+ if (chars[i] != '"') {
+ newChars[j++] = chars[i];
+ } else {
+ newChars[j++] = '\\';
+ newChars[j++] = chars[i];
+ }
+ }
+ name = new String(newChars);
+ }
+ out.print(name);
+ out.print('"');
+ }
+ if (action != null) {
+ out.print(", \"");
+ out.print(action);
+ out.print('"');
+ }
+ if (signedBy != null) {
+ out.print(", signedBy \"");
+ out.print(signedBy);
+ out.print('"');
+ }
+ out.println(";");
+ }
+ }
+
+ static class ParsingException extends GeneralSecurityException {
+
+ private static final long serialVersionUID = 8240970523155877400L;
+
+ /**
+ * Constructs a ParsingException with the specified
+ * detail message. A detail message is a String that describes
+ * this particular exception, which may, for example, specify which
+ * algorithm is not available.
+ *
+ * @param msg the detail message.
+ */
+ public ParsingException(String msg) {
+ super(msg);
+ }
+
+ public ParsingException(int line, String msg) {
+ super(rb.getString("line ") + line + rb.getString(": ") + msg);
+ }
+
+ public ParsingException(int line, String expect, String actual) {
+ super(rb.getString("line ") + line + rb.getString(": expected '") +
+ expect + rb.getString("', found '") + actual +
+ rb.getString("'"));
+ }
+ }
+
+ public static void main(String arg[]) throws Exception {
+ PolicyParser pp = new PolicyParser(true);
+ pp.read(new FileReader(arg[0]));
+ FileWriter fr = new FileWriter(arg[1]);
+ pp.write(fr);
+ fr.close();
+ }
+}