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