jdk/src/share/classes/com/sun/security/auth/PolicyParser.java
changeset 19448 f7bcbf987d5c
parent 19353 ee92e7cf8d35
parent 19447 f2da7f97e104
child 19450 e92c5abf8936
child 19595 4565983c4629
child 19779 fe0b98be61a0
child 20101 4d045bddfaa4
equal deleted inserted replaced
19353:ee92e7cf8d35 19448:f7bcbf987d5c
     1 /*
       
     2  * Copyright (c) 1998, 2011, Oracle and/or its affiliates. All rights reserved.
       
     3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
       
     4  *
       
     5  * This code is free software; you can redistribute it and/or modify it
       
     6  * under the terms of the GNU General Public License version 2 only, as
       
     7  * published by the Free Software Foundation.  Oracle designates this
       
     8  * particular file as subject to the "Classpath" exception as provided
       
     9  * by Oracle in the LICENSE file that accompanied this code.
       
    10  *
       
    11  * This code is distributed in the hope that it will be useful, but WITHOUT
       
    12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
       
    13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
       
    14  * version 2 for more details (a copy is included in the LICENSE file that
       
    15  * accompanied this code).
       
    16  *
       
    17  * You should have received a copy of the GNU General Public License version
       
    18  * 2 along with this work; if not, write to the Free Software Foundation,
       
    19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
       
    20  *
       
    21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
       
    22  * or visit www.oracle.com if you need additional information or have any
       
    23  * questions.
       
    24  */
       
    25 
       
    26 package com.sun.security.auth;
       
    27 
       
    28 import java.io.*;
       
    29 import java.lang.RuntimePermission;
       
    30 import java.net.MalformedURLException;
       
    31 import java.net.SocketPermission;
       
    32 import java.net.URL;
       
    33 import java.security.GeneralSecurityException;
       
    34 import java.text.MessageFormat;
       
    35 import java.util.Enumeration;
       
    36 import java.util.Hashtable;
       
    37 import java.util.LinkedList;
       
    38 import java.util.ListIterator;
       
    39 import java.util.Vector;
       
    40 import java.util.StringTokenizer;
       
    41 import sun.security.util.PropertyExpander;
       
    42 
       
    43 /**
       
    44  * The policy for a Java runtime (specifying
       
    45  * which permissions are available for code from various principals)
       
    46  * is represented as a separate
       
    47  * persistent configuration.  The configuration may be stored as a
       
    48  * flat ASCII file, as a serialized binary file of
       
    49  * the Policy class, or as a database. <p>
       
    50  *
       
    51  * <p>The Java runtime creates one global Policy object, which is used to
       
    52  * represent the static policy configuration file.  It is consulted by
       
    53  * a ProtectionDomain when the protection domain initializes its set of
       
    54  * permissions. <p>
       
    55  *
       
    56  * <p>The Policy <code>init</code> method parses the policy
       
    57  * configuration file, and then
       
    58  * populates the Policy object.  The Policy object is agnostic in that
       
    59  * it is not involved in making policy decisions.  It is merely the
       
    60  * Java runtime representation of the persistent policy configuration
       
    61  * file. <p>
       
    62  *
       
    63  * <p>When a protection domain needs to initialize its set of
       
    64  * permissions, it executes code such as the following
       
    65  * to ask the global Policy object to populate a
       
    66  * Permissions object with the appropriate permissions:
       
    67  * <pre>
       
    68  *  policy = Policy.getPolicy();
       
    69  *  Permissions perms = policy.getPermissions(MyCodeSource)
       
    70  * </pre>
       
    71  *
       
    72  * <p>The protection domain passes in a CodeSource
       
    73  * object, which encapsulates its codebase (URL) and public key attributes.
       
    74  * The Policy object evaluates the global policy in light of who the
       
    75  * principal is and returns an appropriate Permissions object.
       
    76  *
       
    77  * @deprecated As of JDK&nbsp;1.4, replaced by
       
    78  *             {@link sun.security.provider.PolicyParser}.
       
    79  *             This class is entirely deprecated.
       
    80  *
       
    81  * @author Roland Schemers
       
    82  *
       
    83  * @since 1.2
       
    84  */
       
    85 @Deprecated
       
    86 class PolicyParser {
       
    87 
       
    88     private static final java.util.ResourceBundle rb =
       
    89         java.security.AccessController.doPrivileged
       
    90         (new java.security.PrivilegedAction<java.util.ResourceBundle>() {
       
    91             public java.util.ResourceBundle run() {
       
    92                     return (java.util.ResourceBundle.getBundle
       
    93                                 ("sun.security.util.AuthResources"));
       
    94            }
       
    95         });
       
    96 
       
    97     private Vector<GrantEntry> grantEntries;
       
    98 
       
    99     // Convenience variables for parsing
       
   100     private static final sun.security.util.Debug debug =
       
   101         sun.security.util.Debug.getInstance("parser", "\t[Auth Policy Parser]");
       
   102     private StreamTokenizer st;
       
   103     private int lookahead;
       
   104     private int linenum;
       
   105     private boolean expandProp = false;
       
   106     private String keyStoreUrlString = null; // unexpanded
       
   107     private String keyStoreType = null;
       
   108 
       
   109     private String expand(String value)
       
   110         throws PropertyExpander.ExpandException
       
   111     {
       
   112         if (expandProp)
       
   113             return PropertyExpander.expand(value);
       
   114         else
       
   115             return value;
       
   116     }
       
   117     /**
       
   118      * Creates a PolicyParser object.
       
   119      */
       
   120 
       
   121     public PolicyParser() {
       
   122         grantEntries = new Vector<GrantEntry>();
       
   123     }
       
   124 
       
   125 
       
   126     public PolicyParser(boolean expandProp) {
       
   127         this();
       
   128         this.expandProp = expandProp;
       
   129     }
       
   130 
       
   131     /**
       
   132      * Reads a policy configuration into the Policy object using a
       
   133      * Reader object. <p>
       
   134      *
       
   135      * @param policy the policy Reader object.
       
   136      *
       
   137      * @exception ParsingException if the policy configuration contains
       
   138      *          a syntax error.
       
   139      *
       
   140      * @exception IOException if an error occurs while reading the policy
       
   141      *          configuration.
       
   142      */
       
   143 
       
   144     public void read(Reader policy)
       
   145         throws ParsingException, IOException
       
   146     {
       
   147         if (!(policy instanceof BufferedReader)) {
       
   148             policy = new BufferedReader(policy);
       
   149         }
       
   150 
       
   151         /**
       
   152          * Configure the stream tokenizer:
       
   153          *      Recognize strings between "..."
       
   154          *      Don't convert words to lowercase
       
   155          *      Recognize both C-style and C++-style comments
       
   156          *      Treat end-of-line as white space, not as a token
       
   157          */
       
   158         st   = new StreamTokenizer(policy);
       
   159 
       
   160         st.resetSyntax();
       
   161         st.wordChars('a', 'z');
       
   162         st.wordChars('A', 'Z');
       
   163         st.wordChars('.', '.');
       
   164         st.wordChars('0', '9');
       
   165         st.wordChars('_', '_');
       
   166         st.wordChars('$', '$');
       
   167         st.wordChars(128 + 32, 255);
       
   168         st.whitespaceChars(0, ' ');
       
   169         st.commentChar('/');
       
   170         st.quoteChar('\'');
       
   171         st.quoteChar('"');
       
   172         st.lowerCaseMode(false);
       
   173         st.ordinaryChar('/');
       
   174         st.slashSlashComments(true);
       
   175         st.slashStarComments(true);
       
   176 
       
   177         /**
       
   178          * The main parsing loop.  The loop is executed once
       
   179          * for each entry in the config file.      The entries
       
   180          * are delimited by semicolons.   Once we've read in
       
   181          * the information for an entry, go ahead and try to
       
   182          * add it to the policy vector.
       
   183          *
       
   184          */
       
   185 
       
   186         lookahead = st.nextToken();
       
   187         while (lookahead != StreamTokenizer.TT_EOF) {
       
   188             if (peek("grant")) {
       
   189                 GrantEntry ge = parseGrantEntry();
       
   190                 // could be null if we couldn't expand a property
       
   191                 if (ge != null)
       
   192                     add(ge);
       
   193             } else if (peek("keystore") && keyStoreUrlString==null) {
       
   194                 // only one keystore entry per policy file, others will be
       
   195                 // ignored
       
   196                 parseKeyStoreEntry();
       
   197             } else {
       
   198                 // error?
       
   199             }
       
   200             match(";");
       
   201         }
       
   202     }
       
   203 
       
   204     public void add(GrantEntry ge)
       
   205     {
       
   206         grantEntries.addElement(ge);
       
   207     }
       
   208 
       
   209     public void replace(GrantEntry origGe, GrantEntry newGe)
       
   210     {
       
   211         grantEntries.setElementAt(newGe, grantEntries.indexOf(origGe));
       
   212     }
       
   213 
       
   214     public boolean remove(GrantEntry ge)
       
   215     {
       
   216         return grantEntries.removeElement(ge);
       
   217     }
       
   218 
       
   219     /**
       
   220      * Returns the (possibly expanded) keystore location, or null if the
       
   221      * expansion fails.
       
   222      */
       
   223     public String getKeyStoreUrl() {
       
   224         try {
       
   225             if (keyStoreUrlString!=null && keyStoreUrlString.length()!=0) {
       
   226                 return expand(keyStoreUrlString).replace(File.separatorChar,
       
   227                                                          '/');
       
   228             }
       
   229         } catch (PropertyExpander.ExpandException peee) {
       
   230             return null;
       
   231         }
       
   232         return null;
       
   233     }
       
   234 
       
   235     public void setKeyStoreUrl(String url) {
       
   236         keyStoreUrlString = url;
       
   237     }
       
   238 
       
   239     public String getKeyStoreType() {
       
   240         return keyStoreType;
       
   241     }
       
   242 
       
   243     public void setKeyStoreType(String type) {
       
   244         keyStoreType = type;
       
   245     }
       
   246 
       
   247     /**
       
   248      * Enumerate all the entries in the global policy object.
       
   249      * This method is used by policy admin tools.   The tools
       
   250      * should use the Enumeration methods on the returned object
       
   251      * to fetch the elements sequentially.
       
   252      */
       
   253     public Enumeration<GrantEntry> grantElements(){
       
   254         return grantEntries.elements();
       
   255     }
       
   256 
       
   257     /**
       
   258      * write out the policy
       
   259      */
       
   260 
       
   261     public void write(Writer policy)
       
   262     {
       
   263         PrintWriter out = new PrintWriter(new BufferedWriter(policy));
       
   264 
       
   265         Enumeration<GrantEntry> enum_ = grantElements();
       
   266 
       
   267         out.println("/* AUTOMATICALLY GENERATED ON "+
       
   268                     (new java.util.Date()) + "*/");
       
   269         out.println("/* DO NOT EDIT */");
       
   270         out.println();
       
   271 
       
   272         // write the (unexpanded) keystore entry as the first entry of the
       
   273         // policy file
       
   274         if (keyStoreUrlString != null) {
       
   275             writeKeyStoreEntry(out);
       
   276         }
       
   277 
       
   278         // write "grant" entries
       
   279         while (enum_.hasMoreElements()) {
       
   280             GrantEntry ge = enum_.nextElement();
       
   281             ge.write(out);
       
   282             out.println();
       
   283         }
       
   284         out.flush();
       
   285     }
       
   286 
       
   287     /**
       
   288      * parses a keystore entry
       
   289      */
       
   290     private void parseKeyStoreEntry() throws ParsingException, IOException {
       
   291         match("keystore");
       
   292         keyStoreUrlString = match("quoted string");
       
   293 
       
   294         // parse keystore type
       
   295         if (!peek(",")) {
       
   296             return; // default type
       
   297         }
       
   298         match(",");
       
   299 
       
   300         if (peek("\"")) {
       
   301             keyStoreType = match("quoted string");
       
   302         } else {
       
   303             throw new ParsingException(st.lineno(),
       
   304                         rb.getString("expected.keystore.type"));
       
   305         }
       
   306     }
       
   307 
       
   308     /**
       
   309      * writes the (unexpanded) keystore entry
       
   310      */
       
   311     private void writeKeyStoreEntry(PrintWriter out) {
       
   312         out.print("keystore \"");
       
   313         out.print(keyStoreUrlString);
       
   314         out.print('"');
       
   315         if (keyStoreType != null && keyStoreType.length() > 0)
       
   316             out.print(", \"" + keyStoreType + "\"");
       
   317         out.println(";");
       
   318         out.println();
       
   319     }
       
   320 
       
   321     /**
       
   322      * parse a Grant entry
       
   323      */
       
   324     private GrantEntry parseGrantEntry()
       
   325         throws ParsingException, IOException
       
   326     {
       
   327         GrantEntry e = new GrantEntry();
       
   328         LinkedList<PrincipalEntry> principals = null;
       
   329         boolean ignoreEntry = false;
       
   330 
       
   331         match("grant");
       
   332 
       
   333         while(!peek("{")) {
       
   334 
       
   335             if (peekAndMatch("Codebase")) {
       
   336                 e.codeBase = match("quoted string");
       
   337                 peekAndMatch(",");
       
   338             } else if (peekAndMatch("SignedBy")) {
       
   339                 e.signedBy = match("quoted string");
       
   340                 peekAndMatch(",");
       
   341             } else if (peekAndMatch("Principal")) {
       
   342                 if (principals == null) {
       
   343                     principals = new LinkedList<PrincipalEntry>();
       
   344                 }
       
   345 
       
   346                 // check for principalClass wildcard
       
   347                 String principalClass;
       
   348                 if (peek("*")) {
       
   349                     match("*");
       
   350                     principalClass = PrincipalEntry.WILDCARD_CLASS;
       
   351                 } else {
       
   352                     principalClass = match("principal type");
       
   353                 }
       
   354 
       
   355                 // check for principalName wildcard
       
   356                 String principalName;
       
   357                 if (peek("*")) {
       
   358                     match("*");
       
   359                     principalName = PrincipalEntry.WILDCARD_NAME;
       
   360                 } else {
       
   361                     principalName = match("quoted string");
       
   362                 }
       
   363 
       
   364                 // disallow WILDCARD_CLASS && actual name
       
   365                 if (principalClass.equals(PrincipalEntry.WILDCARD_CLASS) &&
       
   366                     !principalName.equals(PrincipalEntry.WILDCARD_NAME)) {
       
   367                     if (debug != null)
       
   368                         debug.println("disallowing principal that has " +
       
   369                                 "WILDCARD class but no WILDCARD name");
       
   370                     throw new ParsingException
       
   371                         (st.lineno(),
       
   372                         rb.getString("can.not.specify.Principal.with.a." +
       
   373                                      "wildcard.class.without.a.wildcard.name"));
       
   374                 }
       
   375 
       
   376                 try {
       
   377                     principalName = expand(principalName);
       
   378                     principals.add
       
   379                         (new PrincipalEntry(principalClass, principalName));
       
   380                 } catch (PropertyExpander.ExpandException peee) {
       
   381                     // ignore the entire policy entry
       
   382                     // but continue parsing all the info
       
   383                     // so we can get to the next entry
       
   384                     if (debug != null)
       
   385                         debug.println("principal name expansion failed: " +
       
   386                                         principalName);
       
   387                     ignoreEntry = true;
       
   388                 }
       
   389                 peekAndMatch(",");
       
   390             } else {
       
   391                 throw new
       
   392                  ParsingException(st.lineno(),
       
   393                         rb.getString("expected.codeBase.or.SignedBy"));
       
   394             }
       
   395         }
       
   396 
       
   397         // disallow non principal-based grant entries
       
   398         if (principals == null) {
       
   399             throw new ParsingException
       
   400                 (st.lineno(),
       
   401                 rb.getString("only.Principal.based.grant.entries.permitted"));
       
   402         }
       
   403 
       
   404         e.principals = principals;
       
   405         match("{");
       
   406 
       
   407         while(!peek("}")) {
       
   408             if (peek("Permission")) {
       
   409                 try {
       
   410                     PermissionEntry pe = parsePermissionEntry();
       
   411                     e.add(pe);
       
   412                 } catch (PropertyExpander.ExpandException peee) {
       
   413                     // ignore. The add never happened
       
   414                     skipEntry();  // BugId 4219343
       
   415                 }
       
   416                 match(";");
       
   417             } else {
       
   418                 throw new
       
   419                     ParsingException(st.lineno(),
       
   420                     rb.getString("expected.permission.entry"));
       
   421             }
       
   422         }
       
   423         match("}");
       
   424 
       
   425         try {
       
   426             if (e.codeBase != null)
       
   427               e.codeBase = expand(e.codeBase).replace(File.separatorChar, '/');
       
   428             e.signedBy = expand(e.signedBy);
       
   429         } catch (PropertyExpander.ExpandException peee) {
       
   430             return null;
       
   431         }
       
   432 
       
   433         return (ignoreEntry == true) ? null : e;
       
   434     }
       
   435 
       
   436     /**
       
   437      * parse a Permission entry
       
   438      */
       
   439     private PermissionEntry parsePermissionEntry()
       
   440         throws ParsingException, IOException, PropertyExpander.ExpandException
       
   441     {
       
   442         PermissionEntry e = new PermissionEntry();
       
   443 
       
   444         // Permission
       
   445         match("Permission");
       
   446         e.permission = match("permission type");
       
   447 
       
   448         if (peek("\"")) {
       
   449             // Permission name
       
   450             e.name = expand(match("quoted string"));
       
   451         }
       
   452 
       
   453         if (!peek(",")) {
       
   454             return e;
       
   455         }
       
   456         match(",");
       
   457 
       
   458         if (peek("\"")) {
       
   459                 e.action = expand(match("quoted string"));
       
   460                 if (!peek(",")) {
       
   461                     return e;
       
   462                 }
       
   463                 match(",");
       
   464         }
       
   465 
       
   466         if (peekAndMatch("SignedBy")) {
       
   467             e.signedBy = expand(match("quoted string"));
       
   468         }
       
   469         return e;
       
   470     }
       
   471 
       
   472     private boolean peekAndMatch(String expect)
       
   473         throws ParsingException, IOException
       
   474     {
       
   475         if (peek(expect)) {
       
   476             match(expect);
       
   477             return true;
       
   478         } else {
       
   479             return false;
       
   480         }
       
   481     }
       
   482 
       
   483     private boolean peek(String expect) {
       
   484         boolean found = false;
       
   485 
       
   486         switch (lookahead) {
       
   487 
       
   488         case StreamTokenizer.TT_WORD:
       
   489             if (expect.equalsIgnoreCase(st.sval))
       
   490                 found = true;
       
   491             break;
       
   492         case ',':
       
   493             if (expect.equalsIgnoreCase(","))
       
   494                 found = true;
       
   495             break;
       
   496         case '{':
       
   497             if (expect.equalsIgnoreCase("{"))
       
   498                 found = true;
       
   499             break;
       
   500         case '}':
       
   501             if (expect.equalsIgnoreCase("}"))
       
   502                 found = true;
       
   503             break;
       
   504         case '"':
       
   505             if (expect.equalsIgnoreCase("\""))
       
   506                 found = true;
       
   507             break;
       
   508         case '*':
       
   509             if (expect.equalsIgnoreCase("*"))
       
   510                 found = true;
       
   511             break;
       
   512         default:
       
   513 
       
   514         }
       
   515         return found;
       
   516     }
       
   517 
       
   518     private String match(String expect)
       
   519         throws ParsingException, IOException
       
   520     {
       
   521         String value = null;
       
   522 
       
   523         switch (lookahead) {
       
   524         case StreamTokenizer.TT_NUMBER:
       
   525             throw new ParsingException(st.lineno(), expect,
       
   526                                         rb.getString("number.") +
       
   527                                         String.valueOf(st.nval));
       
   528         case StreamTokenizer.TT_EOF:
       
   529             MessageFormat form = new MessageFormat(
       
   530                     rb.getString("expected.expect.read.end.of.file."));
       
   531             Object[] source = {expect};
       
   532             throw new ParsingException(form.format(source));
       
   533         case StreamTokenizer.TT_WORD:
       
   534             if (expect.equalsIgnoreCase(st.sval)) {
       
   535                 lookahead = st.nextToken();
       
   536             } else if (expect.equalsIgnoreCase("permission type")) {
       
   537                 value = st.sval;
       
   538                 lookahead = st.nextToken();
       
   539             } else if (expect.equalsIgnoreCase("principal type")) {
       
   540                 value = st.sval;
       
   541                 lookahead = st.nextToken();
       
   542             } else {
       
   543                 throw new ParsingException(st.lineno(), expect, st.sval);
       
   544             }
       
   545             break;
       
   546         case '"':
       
   547             if (expect.equalsIgnoreCase("quoted string")) {
       
   548                 value = st.sval;
       
   549                 lookahead = st.nextToken();
       
   550             } else if (expect.equalsIgnoreCase("permission type")) {
       
   551                 value = st.sval;
       
   552                 lookahead = st.nextToken();
       
   553             } else if (expect.equalsIgnoreCase("principal type")) {
       
   554                 value = st.sval;
       
   555                 lookahead = st.nextToken();
       
   556             } else {
       
   557                 throw new ParsingException(st.lineno(), expect, st.sval);
       
   558             }
       
   559             break;
       
   560         case ',':
       
   561             if (expect.equalsIgnoreCase(","))
       
   562                 lookahead = st.nextToken();
       
   563             else
       
   564                 throw new ParsingException(st.lineno(), expect, ",");
       
   565             break;
       
   566         case '{':
       
   567             if (expect.equalsIgnoreCase("{"))
       
   568                 lookahead = st.nextToken();
       
   569             else
       
   570                 throw new ParsingException(st.lineno(), expect, "{");
       
   571             break;
       
   572         case '}':
       
   573             if (expect.equalsIgnoreCase("}"))
       
   574                 lookahead = st.nextToken();
       
   575             else
       
   576                 throw new ParsingException(st.lineno(), expect, "}");
       
   577             break;
       
   578         case ';':
       
   579             if (expect.equalsIgnoreCase(";"))
       
   580                 lookahead = st.nextToken();
       
   581             else
       
   582                 throw new ParsingException(st.lineno(), expect, ";");
       
   583             break;
       
   584         case '*':
       
   585             if (expect.equalsIgnoreCase("*"))
       
   586                 lookahead = st.nextToken();
       
   587             else
       
   588                 throw new ParsingException(st.lineno(), expect, "*");
       
   589             break;
       
   590         default:
       
   591             throw new ParsingException(st.lineno(), expect,
       
   592                                new String(new char[] {(char)lookahead}));
       
   593         }
       
   594         return value;
       
   595     }
       
   596 
       
   597     /**
       
   598      * skip all tokens for this entry leaving the delimiter ";"
       
   599      * in the stream.
       
   600      */
       
   601     private void skipEntry()
       
   602         throws ParsingException, IOException
       
   603     {
       
   604       while(lookahead != ';') {
       
   605         switch (lookahead) {
       
   606         case StreamTokenizer.TT_NUMBER:
       
   607             throw new ParsingException(st.lineno(), ";",
       
   608                                        rb.getString("number.") +
       
   609                                         String.valueOf(st.nval));
       
   610         case StreamTokenizer.TT_EOF:
       
   611           throw new ParsingException
       
   612                 (rb.getString("expected.read.end.of.file"));
       
   613         default:
       
   614           lookahead = st.nextToken();
       
   615         }
       
   616       }
       
   617     }
       
   618 
       
   619     /**
       
   620      * Each grant entry in the policy configuration file is
       
   621      * represented by a
       
   622      * GrantEntry object.  <p>
       
   623      *
       
   624      * <p>
       
   625      * For example, the entry
       
   626      * <pre>
       
   627      *      grant signedBy "Duke" {
       
   628      *          permission java.io.FilePermission "/tmp", "read,write";
       
   629      *      };
       
   630      *
       
   631      * </pre>
       
   632      * is represented internally
       
   633      * <pre>
       
   634      *
       
   635      * pe = new PermissionEntry("java.io.FilePermission",
       
   636      *                           "/tmp", "read,write");
       
   637      *
       
   638      * ge = new GrantEntry("Duke", null);
       
   639      *
       
   640      * ge.add(pe);
       
   641      *
       
   642      * </pre>
       
   643      *
       
   644      * @author Roland Schemers
       
   645      *
       
   646      * version 1.19, 05/21/98
       
   647      */
       
   648 
       
   649     static class GrantEntry {
       
   650 
       
   651         public String signedBy;
       
   652         public String codeBase;
       
   653         public LinkedList<PrincipalEntry> principals;
       
   654         public Vector<PermissionEntry> permissionEntries;
       
   655 
       
   656         public GrantEntry() {
       
   657             permissionEntries = new Vector<PermissionEntry>();
       
   658         }
       
   659 
       
   660         public GrantEntry(String signedBy, String codeBase) {
       
   661             this.codeBase = codeBase;
       
   662             this.signedBy = signedBy;
       
   663             permissionEntries = new Vector<PermissionEntry>();
       
   664         }
       
   665 
       
   666         public void add(PermissionEntry pe)
       
   667         {
       
   668             permissionEntries.addElement(pe);
       
   669         }
       
   670 
       
   671         public boolean remove(PermissionEntry pe)
       
   672         {
       
   673             return permissionEntries.removeElement(pe);
       
   674         }
       
   675 
       
   676         public boolean contains(PermissionEntry pe)
       
   677         {
       
   678             return permissionEntries.contains(pe);
       
   679         }
       
   680 
       
   681         /**
       
   682          * Enumerate all the permission entries in this GrantEntry.
       
   683          */
       
   684         public Enumeration<PermissionEntry> permissionElements(){
       
   685             return permissionEntries.elements();
       
   686         }
       
   687 
       
   688 
       
   689         public void write(PrintWriter out) {
       
   690             out.print("grant");
       
   691             if (signedBy != null) {
       
   692                 out.print(" signedBy \"");
       
   693                 out.print(signedBy);
       
   694                 out.print('"');
       
   695                 if (codeBase != null)
       
   696                     out.print(", ");
       
   697             }
       
   698             if (codeBase != null) {
       
   699                 out.print(" codeBase \"");
       
   700                 out.print(codeBase);
       
   701                 out.print('"');
       
   702                 if (principals != null && principals.size() > 0)
       
   703                     out.print(",\n");
       
   704             }
       
   705             if (principals != null && principals.size() > 0) {
       
   706                 ListIterator<PrincipalEntry> pli = principals.listIterator();
       
   707                 while (pli.hasNext()) {
       
   708                     out.print("\tPrincipal ");
       
   709                     PrincipalEntry pe = pli.next();
       
   710                     out.print(pe.principalClass +
       
   711                                 " \"" + pe.principalName + "\"");
       
   712                     if (pli.hasNext())
       
   713                         out.print(",\n");
       
   714                 }
       
   715             }
       
   716             out.println(" {");
       
   717             Enumeration<PermissionEntry> enum_ = permissionEntries.elements();
       
   718             while (enum_.hasMoreElements()) {
       
   719                 PermissionEntry pe = enum_.nextElement();
       
   720                 out.write("  ");
       
   721                 pe.write(out);
       
   722             }
       
   723             out.println("};");
       
   724         }
       
   725 
       
   726     }
       
   727 
       
   728     /**
       
   729      * Principal info (class and name) in a grant entry
       
   730      */
       
   731     static class PrincipalEntry {
       
   732 
       
   733         static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS";
       
   734         static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME";
       
   735 
       
   736         String principalClass;
       
   737         String principalName;
       
   738 
       
   739         /**
       
   740          * A PrincipalEntry consists of the <code>Principal</code>
       
   741          * class and <code>Principal</code> name.
       
   742          *
       
   743          * <p>
       
   744          *
       
   745          * @param principalClass the <code>Principal</code> class. <p>
       
   746          *
       
   747          * @param principalName the <code>Principal</code> name. <p>
       
   748          */
       
   749         public PrincipalEntry(String principalClass, String principalName) {
       
   750             if (principalClass == null || principalName == null)
       
   751                 throw new NullPointerException
       
   752                         ("null principalClass or principalName");
       
   753             this.principalClass = principalClass;
       
   754             this.principalName = principalName;
       
   755         }
       
   756 
       
   757         /**
       
   758          * Test for equality between the specified object and this object.
       
   759          * Two PrincipalEntries are equal if their PrincipalClass and
       
   760          * PrincipalName values are equal.
       
   761          *
       
   762          * <p>
       
   763          *
       
   764          * @param obj the object to test for equality with this object.
       
   765          *
       
   766          * @return true if the objects are equal, false otherwise.
       
   767          */
       
   768         public boolean equals(Object obj) {
       
   769             if (this == obj)
       
   770                 return true;
       
   771 
       
   772             if (!(obj instanceof PrincipalEntry))
       
   773                 return false;
       
   774 
       
   775             PrincipalEntry that = (PrincipalEntry)obj;
       
   776             if (this.principalClass.equals(that.principalClass) &&
       
   777                 this.principalName.equals(that.principalName)) {
       
   778                 return true;
       
   779             }
       
   780 
       
   781             return false;
       
   782         }
       
   783 
       
   784         /**
       
   785          * Return a hashcode for this <code>PrincipalEntry</code>.
       
   786          *
       
   787          * <p>
       
   788          *
       
   789          * @return a hashcode for this <code>PrincipalEntry</code>.
       
   790          */
       
   791         public int hashCode() {
       
   792             return principalClass.hashCode();
       
   793         }
       
   794     }
       
   795 
       
   796     /**
       
   797      * Each permission entry in the policy configuration file is
       
   798      * represented by a
       
   799      * PermissionEntry object.  <p>
       
   800      *
       
   801      * <p>
       
   802      * For example, the entry
       
   803      * <pre>
       
   804      *          permission java.io.FilePermission "/tmp", "read,write";
       
   805      * </pre>
       
   806      * is represented internally
       
   807      * <pre>
       
   808      *
       
   809      * pe = new PermissionEntry("java.io.FilePermission",
       
   810      *                           "/tmp", "read,write");
       
   811      * </pre>
       
   812      *
       
   813      * @author Roland Schemers
       
   814      *
       
   815      * version 1.19, 05/21/98
       
   816      */
       
   817 
       
   818     static class PermissionEntry {
       
   819 
       
   820         public String permission;
       
   821         public String name;
       
   822         public String action;
       
   823         public String signedBy;
       
   824 
       
   825         public PermissionEntry() {
       
   826         }
       
   827 
       
   828         public PermissionEntry(String permission,
       
   829                         String name,
       
   830                         String action) {
       
   831             this.permission = permission;
       
   832             this.name = name;
       
   833             this.action = action;
       
   834         }
       
   835 
       
   836         /**
       
   837          * Calculates a hash code value for the object.  Objects
       
   838          * which are equal will also have the same hashcode.
       
   839          */
       
   840         public int hashCode() {
       
   841             int retval = permission.hashCode();
       
   842             if (name != null) retval ^= name.hashCode();
       
   843             if (action != null) retval ^= action.hashCode();
       
   844             return retval;
       
   845         }
       
   846 
       
   847         public boolean equals(Object obj) {
       
   848             if (obj == this)
       
   849                 return true;
       
   850 
       
   851             if (! (obj instanceof PermissionEntry))
       
   852                 return false;
       
   853 
       
   854             PermissionEntry that = (PermissionEntry) obj;
       
   855 
       
   856             if (this.permission == null) {
       
   857                 if (that.permission != null) return false;
       
   858             } else {
       
   859                 if (!this.permission.equals(that.permission)) return false;
       
   860             }
       
   861 
       
   862             if (this.name == null) {
       
   863                 if (that.name != null) return false;
       
   864             } else {
       
   865                 if (!this.name.equals(that.name)) return false;
       
   866             }
       
   867 
       
   868             if (this.action == null) {
       
   869                 if (that.action != null) return false;
       
   870             } else {
       
   871                 if (!this.action.equals(that.action)) return false;
       
   872             }
       
   873 
       
   874             if (this.signedBy == null) {
       
   875                 if (that.signedBy != null) return false;
       
   876             } else {
       
   877                 if (!this.signedBy.equals(that.signedBy)) return false;
       
   878             }
       
   879 
       
   880             // everything matched -- the 2 objects are equal
       
   881             return true;
       
   882         }
       
   883 
       
   884         public void write(PrintWriter out) {
       
   885             out.print("permission ");
       
   886             out.print(permission);
       
   887             if (name != null) {
       
   888                 out.print(" \"");
       
   889 
       
   890                 // have to add escape chars for quotes
       
   891                 if (name.indexOf("\"") != -1) {
       
   892                     int numQuotes = 0;
       
   893                     char[] chars = name.toCharArray();
       
   894 
       
   895                     // count the number of quote chars
       
   896                     for (int i = 0; i < chars.length; i++) {
       
   897                         if (chars[i] == '"')
       
   898                             numQuotes++;
       
   899                     }
       
   900 
       
   901                     // now, add an escape char before each quote
       
   902                     char[] newChars = new char[chars.length + numQuotes];
       
   903                     for (int i = 0, j = 0; i < chars.length; i++) {
       
   904                         if (chars[i] != '"') {
       
   905                             newChars[j++] = chars[i];
       
   906                         } else {
       
   907                             newChars[j++] = '\\';
       
   908                             newChars[j++] = chars[i];
       
   909                         }
       
   910                     }
       
   911                     name = new String(newChars);
       
   912                 }
       
   913                 out.print(name);
       
   914                 out.print('"');
       
   915             }
       
   916             if (action != null) {
       
   917                 out.print(", \"");
       
   918                 out.print(action);
       
   919                 out.print('"');
       
   920             }
       
   921             if (signedBy != null) {
       
   922                 out.print(", signedBy \"");
       
   923                 out.print(signedBy);
       
   924                 out.print('"');
       
   925             }
       
   926             out.println(";");
       
   927         }
       
   928     }
       
   929 
       
   930     static class ParsingException extends GeneralSecurityException {
       
   931 
       
   932         private static final long serialVersionUID = 8240970523155877400L;
       
   933 
       
   934         /**
       
   935          * Constructs a ParsingException with the specified
       
   936          * detail message. A detail message is a String that describes
       
   937          * this particular exception, which may, for example, specify which
       
   938          * algorithm is not available.
       
   939          *
       
   940          * @param msg the detail message.
       
   941          */
       
   942         public ParsingException(String msg) {
       
   943             super(msg);
       
   944         }
       
   945 
       
   946         public ParsingException(int line, String msg) {
       
   947             super(rb.getString("line.") + line + rb.getString("COLON") + msg);
       
   948         }
       
   949 
       
   950         public ParsingException(int line, String expect, String actual) {
       
   951             super(rb.getString("line.") + line + rb.getString(".expected.") +
       
   952                 expect + rb.getString(".found.") + actual +
       
   953                 rb.getString("QUOTE"));
       
   954         }
       
   955     }
       
   956 
       
   957     public static void main(String arg[]) throws Exception {
       
   958         PolicyParser pp = new PolicyParser(true);
       
   959         pp.read(new FileReader(arg[0]));
       
   960         FileWriter fr = new FileWriter(arg[1]);
       
   961         pp.write(fr);
       
   962         fr.close();
       
   963     }
       
   964 }