| /* |
| * Copyright (c) 1997, 2006, Oracle and/or its affiliates. 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. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package sun.security.provider; |
| |
| import java.io.*; |
| import java.lang.RuntimePermission; |
| 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.text.MessageFormat; |
| import javax.security.auth.x500.X500Principal; |
| |
| import java.security.GeneralSecurityException; |
| import sun.security.util.Debug; |
| import sun.security.util.PropertyExpander; |
| import sun.security.util.ResourcesMgr; |
| |
| /** |
| * 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(protectiondomain) |
| * </pre> |
| * |
| * <p>The protection domain contains CodeSource |
| * object, which encapsulates its codebase (URL) and public key attributes. |
| * It also contains the principals associated with the domain. |
| * The Policy object evaluates the global policy in light of who the |
| * principal is and what the code source is and returns an appropriate |
| * Permissions object. |
| * |
| * @author Roland Schemers |
| * @author Ram Marti |
| * |
| * @since 1.2 |
| */ |
| |
| public class PolicyParser { |
| |
| // needs to be public for PolicyTool |
| public static final String REPLACE_NAME = "PolicyParser.REPLACE_NAME"; |
| |
| private static final String EXTDIRS_PROPERTY = "java.ext.dirs"; |
| private static final String OLD_EXTDIRS_EXPANSION = |
| "${" + EXTDIRS_PROPERTY + "}"; |
| |
| // package-private: used by PolicyFile for static policy |
| static final String EXTDIRS_EXPANSION = "${{" + EXTDIRS_PROPERTY + "}}"; |
| |
| |
| private Vector<GrantEntry> grantEntries; |
| |
| // Convenience variables for parsing |
| private static final Debug debug = Debug.getInstance("parser", |
| "\t[Policy Parser]"); |
| private StreamTokenizer st; |
| private int lookahead; |
| private boolean expandProp = false; |
| private String keyStoreUrlString = null; // unexpanded |
| private String keyStoreType = null; |
| private String keyStoreProvider = null; |
| private String storePassURL = null; |
| |
| private String expand(String value) |
| throws PropertyExpander.ExpandException |
| { |
| return expand(value, false); |
| } |
| |
| private String expand(String value, boolean encodeURL) |
| throws PropertyExpander.ExpandException |
| { |
| if (!expandProp) { |
| return value; |
| } else { |
| return PropertyExpander.expand(value, encodeURL); |
| } |
| } |
| |
| /** |
| * 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 if (peek("keystorePasswordURL") && storePassURL==null) { |
| // only one keystore passwordURL per policy file, others will be |
| // ignored |
| parseStorePassURL(); |
| } else { |
| // error? |
| } |
| match(";"); |
| } |
| |
| if (keyStoreUrlString == null && storePassURL != null) { |
| throw new ParsingException(ResourcesMgr.getString |
| ("keystorePasswordURL can not be specified without also " + |
| "specifying keystore")); |
| } |
| } |
| |
| 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, true).replace |
| (File.separatorChar, '/'); |
| } |
| } catch (PropertyExpander.ExpandException peee) { |
| if (debug != null) { |
| debug.println(peee.toString()); |
| } |
| return null; |
| } |
| return null; |
| } |
| |
| public void setKeyStoreUrl(String url) { |
| keyStoreUrlString = url; |
| } |
| |
| public String getKeyStoreType() { |
| return keyStoreType; |
| } |
| |
| public void setKeyStoreType(String type) { |
| keyStoreType = type; |
| } |
| |
| public String getKeyStoreProvider() { |
| return keyStoreProvider; |
| } |
| |
| public void setKeyStoreProvider(String provider) { |
| keyStoreProvider = provider; |
| } |
| |
| public String getStorePassURL() { |
| try { |
| if (storePassURL!=null && storePassURL.length()!=0) { |
| return expand(storePassURL, true).replace |
| (File.separatorChar, '/'); |
| } |
| } catch (PropertyExpander.ExpandException peee) { |
| if (debug != null) { |
| debug.println(peee.toString()); |
| } |
| return null; |
| } |
| return null; |
| } |
| |
| public void setStorePassURL(String storePassURL) { |
| this.storePassURL = storePassURL; |
| } |
| |
| /** |
| * 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); |
| } |
| if (storePassURL != null) { |
| writeStorePassURL(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(), |
| ResourcesMgr.getString("expected keystore type")); |
| } |
| |
| // parse keystore provider |
| if (!peek(",")) { |
| return; // provider optional |
| } |
| match(","); |
| |
| if (peek("\"")) { |
| keyStoreProvider = match("quoted string"); |
| } else { |
| throw new ParsingException(st.lineno(), |
| ResourcesMgr.getString("expected keystore provider")); |
| } |
| } |
| |
| private void parseStorePassURL() throws ParsingException, IOException { |
| match("keyStorePasswordURL"); |
| storePassURL = match("quoted string"); |
| } |
| |
| /** |
| * 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 + "\""); |
| if (keyStoreProvider != null && keyStoreProvider.length() > 0) |
| out.print(", \"" + keyStoreProvider + "\""); |
| out.println(";"); |
| out.println(); |
| } |
| |
| private void writeStorePassURL(PrintWriter out) { |
| out.print("keystorePasswordURL \""); |
| out.print(storePassURL); |
| out.print('"'); |
| 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")) { |
| if (e.codeBase != null) |
| throw new ParsingException( |
| st.lineno(), |
| ResourcesMgr.getString |
| ("multiple Codebase expressions")); |
| e.codeBase = match("quoted string"); |
| peekAndMatch(","); |
| } else if (peekAndMatch("SignedBy")) { |
| if (e.signedBy != null) |
| throw new ParsingException( |
| st.lineno(), |
| ResourcesMgr.getString( |
| "multiple SignedBy expressions")); |
| e.signedBy = match("quoted string"); |
| |
| // verify syntax of the aliases |
| StringTokenizer aliases = new StringTokenizer(e.signedBy, |
| ",", true); |
| int actr = 0; |
| int cctr = 0; |
| while (aliases.hasMoreTokens()) { |
| String alias = aliases.nextToken().trim(); |
| if (alias.equals(",")) |
| cctr++; |
| else if (alias.length() > 0) |
| actr++; |
| } |
| if (actr <= cctr) |
| throw new ParsingException( |
| st.lineno(), |
| ResourcesMgr.getString( |
| "SignedBy has empty alias")); |
| |
| peekAndMatch(","); |
| } else if (peekAndMatch("Principal")) { |
| if (principals == null) { |
| principals = new LinkedList<PrincipalEntry>(); |
| } |
| |
| String principalClass; |
| String principalName; |
| |
| if (peek("\"")) { |
| // both the principalClass and principalName |
| // will be replaced later |
| principalClass = REPLACE_NAME; |
| principalName = match("principal type"); |
| } else { |
| // check for principalClass wildcard |
| if (peek("*")) { |
| match("*"); |
| principalClass = PrincipalEntry.WILDCARD_CLASS; |
| } else { |
| principalClass = match("principal type"); |
| } |
| |
| // check for principalName wildcard |
| 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(), |
| ResourcesMgr.getString |
| ("can not specify Principal with a " + |
| "wildcard class without a wildcard name")); |
| } |
| } |
| |
| try { |
| principalName = expand(principalName); |
| |
| if (principalClass.equals |
| ("javax.security.auth.x500.X500Principal") && |
| !principalName.equals(PrincipalEntry.WILDCARD_NAME)) { |
| |
| // 4702543: X500 names with an EmailAddress |
| // were encoded incorrectly. construct a new |
| // X500Principal with correct encoding. |
| |
| X500Principal p = new X500Principal |
| ((new X500Principal(principalName)).toString()); |
| principalName = p.getName(); |
| } |
| |
| 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(), |
| ResourcesMgr.getString( |
| "expected codeBase or SignedBy or " + |
| "Principal")); |
| } |
| } |
| |
| if (principals != null) 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 |
| if (debug != null) { |
| debug.println(peee.toString()); |
| } |
| skipEntry(); // BugId 4219343 |
| } |
| match(";"); |
| } else { |
| throw new |
| ParsingException(st.lineno(), |
| ResourcesMgr.getString( |
| "expected permission entry")); |
| } |
| } |
| match("}"); |
| |
| try { |
| if (e.signedBy != null) e.signedBy = expand(e.signedBy); |
| if (e.codeBase != null) { |
| |
| // For backward compatibility with 1.4 |
| if (e.codeBase.equals(OLD_EXTDIRS_EXPANSION)) { |
| e.codeBase = EXTDIRS_EXPANSION; |
| } |
| int es; |
| if ((es=e.codeBase.indexOf(EXTDIRS_EXPANSION)) < 0) { |
| e.codeBase = expand(e.codeBase, true).replace |
| (File.separatorChar, '/'); |
| } else { |
| // expand the system property "java.ext.dirs", |
| // parse it into its path components, |
| // and then create a grant entry for each component |
| String[] extDirs = parseExtDirs(e.codeBase, es); |
| if (extDirs != null && extDirs.length > 0) { |
| for (int i = 0; i < extDirs.length; i++) { |
| GrantEntry newGe = (GrantEntry)e.clone(); |
| newGe.codeBase = extDirs[i]; |
| add(newGe); |
| |
| if (debug != null) { |
| debug.println("creating policy entry for " + |
| "expanded java.ext.dirs path:\n\t\t" + |
| extDirs[i]); |
| } |
| } |
| } |
| ignoreEntry = true; |
| } |
| } |
| } catch (PropertyExpander.ExpandException peee) { |
| if (debug != null) { |
| debug.println(peee.toString()); |
| } |
| 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; |
| } |
| |
| // package-private: used by PolicyFile for static policy |
| static String[] parseExtDirs(String codebase, int start) { |
| |
| String s = System.getProperty(EXTDIRS_PROPERTY); |
| String globalPrefix = (start > 0 ? codebase.substring(0, start) : "file:"); |
| int end = start + EXTDIRS_EXPANSION.length(); |
| String globalSuffix = (end < codebase.length() ? codebase.substring(end) : |
| (String) null); |
| |
| String[] dirs = null; |
| String localSuffix; |
| if (s != null) { |
| StringTokenizer st = |
| new StringTokenizer(s, File.pathSeparator); |
| int count = st.countTokens(); |
| dirs = new String[count]; |
| for (int i = 0; i < count; i++) { |
| File file = new File(st.nextToken()); |
| dirs[i] = sun.net.www.ParseUtil.encodePath |
| (file.getAbsolutePath()); |
| |
| if (!dirs[i].startsWith("/")) { |
| dirs[i] = "/" + dirs[i]; |
| } |
| |
| localSuffix = (globalSuffix == null ? |
| (dirs[i].endsWith("/") ? "*" : "/*") : |
| globalSuffix); |
| |
| dirs[i] = globalPrefix + dirs[i] + localSuffix; |
| } |
| } |
| return dirs; |
| } |
| |
| 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, |
| ResourcesMgr.getString("number ") + |
| String.valueOf(st.nval)); |
| case StreamTokenizer.TT_EOF: |
| MessageFormat form = new MessageFormat( |
| ResourcesMgr.getString |
| ("expected [expect], read [end of file]")); |
| Object[] source = {expect}; |
| throw new ParsingException(form.format(source)); |
| 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(), ";", |
| ResourcesMgr.getString("number ") + |
| String.valueOf(st.nval)); |
| case StreamTokenizer.TT_EOF: |
| throw new ParsingException(ResourcesMgr.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 |
| */ |
| |
| public static class GrantEntry { |
| |
| public String signedBy; |
| public String codeBase; |
| public LinkedList<PrincipalEntry> principals; |
| public Vector<PermissionEntry> permissionEntries; |
| |
| public GrantEntry() { |
| principals = new LinkedList<PrincipalEntry>(); |
| permissionEntries = new Vector<PermissionEntry>(); |
| } |
| |
| public GrantEntry(String signedBy, String codeBase) { |
| this.codeBase = codeBase; |
| this.signedBy = signedBy; |
| principals = new LinkedList<PrincipalEntry>(); |
| permissionEntries = new Vector<PermissionEntry>(); |
| } |
| |
| public void add(PermissionEntry pe) |
| { |
| permissionEntries.addElement(pe); |
| } |
| |
| public boolean remove(PrincipalEntry pe) |
| { |
| return principals.remove(pe); |
| } |
| |
| public boolean remove(PermissionEntry pe) |
| { |
| return permissionEntries.removeElement(pe); |
| } |
| |
| public boolean contains(PrincipalEntry pe) |
| { |
| return principals.contains(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(" "); |
| PrincipalEntry pe = pli.next(); |
| pe.write(out); |
| 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("};"); |
| } |
| |
| public Object clone() { |
| GrantEntry ge = new GrantEntry(); |
| ge.codeBase = this.codeBase; |
| ge.signedBy = this.signedBy; |
| ge.principals = new LinkedList<PrincipalEntry>(this.principals); |
| ge.permissionEntries = |
| new Vector<PermissionEntry>(this.permissionEntries); |
| return ge; |
| } |
| } |
| |
| /** |
| * Principal info (class and name) in a grant entry |
| */ |
| public static class PrincipalEntry { |
| |
| public static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS"; |
| public 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(ResourcesMgr.getString( |
| "null principalClass or principalName")); |
| this.principalClass = principalClass; |
| this.principalName = principalName; |
| } |
| |
| public String getPrincipalClass() { |
| return principalClass; |
| } |
| |
| public String getPrincipalName() { |
| return principalName; |
| } |
| |
| public String getDisplayClass() { |
| if (principalClass.equals(WILDCARD_CLASS)) { |
| return "*"; |
| } else if (principalClass.equals(REPLACE_NAME)) { |
| return ""; |
| } |
| else return principalClass; |
| } |
| |
| public String getDisplayName() { |
| return getDisplayName(false); |
| } |
| |
| public String getDisplayName(boolean addQuote) { |
| if (principalName.equals(WILDCARD_NAME)) { |
| return "*"; |
| } |
| else { |
| if (addQuote) return "\"" + principalName + "\""; |
| else return principalName; |
| } |
| } |
| |
| public String toString() { |
| if (!principalClass.equals(REPLACE_NAME)) { |
| return getDisplayClass() + "/" + getDisplayName(); |
| } else { |
| return getDisplayName(); |
| } |
| } |
| |
| /** |
| * 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(); |
| } |
| public void write(PrintWriter out) { |
| out.print("principal " + getDisplayClass() + " " + |
| getDisplayName(true)); |
| } |
| } |
| |
| /** |
| * 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 |
| */ |
| |
| public 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(" \""); |
| |
| // ATTENTION: regex with double escaping, |
| // the normal forms look like: |
| // $name =~ s/\\/\\\\/g; and |
| // $name =~ s/\"/\\\"/g; |
| // and then in a java string, it's escaped again |
| |
| out.print(name.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\\"", "\\\\\\\"")); |
| 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(";"); |
| } |
| } |
| |
| public static class ParsingException extends GeneralSecurityException { |
| |
| private static final long serialVersionUID = -4330692689482574072L; |
| |
| private String i18nMessage; |
| |
| /** |
| * 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); |
| i18nMessage = msg; |
| } |
| |
| public ParsingException(int line, String msg) { |
| super("line " + line + ": " + msg); |
| MessageFormat form = new MessageFormat |
| (ResourcesMgr.getString("line number: msg")); |
| Object[] source = {new Integer(line), msg}; |
| i18nMessage = form.format(source); |
| } |
| |
| public ParsingException(int line, String expect, String actual) { |
| super("line " + line + ": expected [" + expect + |
| "], found [" + actual + "]"); |
| MessageFormat form = new MessageFormat(ResourcesMgr.getString |
| ("line number: expected [expect], found [actual]")); |
| Object[] source = {new Integer(line), expect, actual}; |
| i18nMessage = form.format(source); |
| } |
| |
| public String getLocalizedMessage() { |
| return i18nMessage; |
| } |
| } |
| |
| public static void main(String arg[]) throws Exception { |
| FileReader fr = null; |
| FileWriter fw = null; |
| try { |
| PolicyParser pp = new PolicyParser(true); |
| fr = new FileReader(arg[0]); |
| pp.read(fr); |
| fw = new FileWriter(arg[1]); |
| pp.write(fw); |
| } finally { |
| if (fr != null) { |
| fr.close(); |
| } |
| |
| if (fw != null) { |
| fw.close(); |
| } |
| } |
| } |
| } |