History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/sun/security/provider/PolicyParser.java (1 of 18352 files). Show all

Unified · Split

java/pkg/sun/security/provider/PolicyParser.java+1237−0
@@ -0,0 +1,1237 @@
1+/*
2+ * Copyright (c) 1997, 2010, 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 sun.security.provider;
27+
28+import java.io.*;
29+import java.lang.RuntimePermission;
30+import java.net.SocketPermission;
31+import java.net.URL;
32+import java.util.Enumeration;
33+import java.util.Hashtable;
34+import java.util.LinkedList;
35+import java.util.ListIterator;
36+import java.util.Vector;
37+import java.util.StringTokenizer;
38+import java.text.MessageFormat;
39+import javax.security.auth.x500.X500Principal;
40+
41+import java.security.GeneralSecurityException;
42+import sun.security.util.Debug;
43+import sun.security.util.PropertyExpander;
44+import sun.security.util.ResourcesMgr;
45+
46+/**
47+ * The policy for a Java runtime (specifying
48+ * which permissions are available for code from various principals)
49+ * is represented as a separate
50+ * persistent configuration. The configuration may be stored as a
51+ * flat ASCII file, as a serialized binary file of
52+ * the Policy class, or as a database. <p>
53+ *
54+ * <p>The Java runtime creates one global Policy object, which is used to
55+ * represent the static policy configuration file. It is consulted by
56+ * a ProtectionDomain when the protection domain initializes its set of
57+ * permissions. <p>
58+ *
59+ * <p>The Policy <code>init</code> method parses the policy
60+ * configuration file, and then
61+ * populates the Policy object. The Policy object is agnostic in that
62+ * it is not involved in making policy decisions. It is merely the
63+ * Java runtime representation of the persistent policy configuration
64+ * file. <p>
65+ *
66+ * <p>When a protection domain needs to initialize its set of
67+ * permissions, it executes code such as the following
68+ * to ask the global Policy object to populate a
69+ * Permissions object with the appropriate permissions:
70+ * <pre>
71+ * policy = Policy.getPolicy();
72+ * Permissions perms = policy.getPermissions(protectiondomain)
73+ * </pre>
74+ *
75+ * <p>The protection domain contains CodeSource
76+ * object, which encapsulates its codebase (URL) and public key attributes.
77+ * It also contains the principals associated with the domain.
78+ * The Policy object evaluates the global policy in light of who the
79+ * principal is and what the code source is and returns an appropriate
80+ * Permissions object.
81+ *
82+ * @author Roland Schemers
83+ * @author Ram Marti
84+ *
85+ * @since 1.2
86+ */
87+
88+public class PolicyParser {
89+
90+ // needs to be public for PolicyTool
91+ public static final String REPLACE_NAME = "PolicyParser.REPLACE_NAME";
92+
93+ private static final String EXTDIRS_PROPERTY = "java.ext.dirs";
94+ private static final String OLD_EXTDIRS_EXPANSION =
95+ "${" + EXTDIRS_PROPERTY + "}";
96+
97+ // package-private: used by PolicyFile for static policy
98+ static final String EXTDIRS_EXPANSION = "${{" + EXTDIRS_PROPERTY + "}}";
99+
100+
101+ private Vector<GrantEntry> grantEntries;
102+
103+ // Convenience variables for parsing
104+ private static final Debug debug = Debug.getInstance("parser",
105+ "\t[Policy Parser]");
106+ private StreamTokenizer st;
107+ private int lookahead;
108+ private boolean expandProp = false;
109+ private String keyStoreUrlString = null; // unexpanded
110+ private String keyStoreType = null;
111+ private String keyStoreProvider = null;
112+ private String storePassURL = null;
113+
114+ private String expand(String value)
115+ throws PropertyExpander.ExpandException
116+ {
117+ return expand(value, false);
118+ }
119+
120+ private String expand(String value, boolean encodeURL)
121+ throws PropertyExpander.ExpandException
122+ {
123+ if (!expandProp) {
124+ return value;
125+ } else {
126+ return PropertyExpander.expand(value, encodeURL);
127+ }
128+ }
129+
130+ /**
131+ * Creates a PolicyParser object.
132+ */
133+
134+ public PolicyParser() {
135+ grantEntries = new Vector<GrantEntry>();
136+ }
137+
138+
139+ public PolicyParser(boolean expandProp) {
140+ this();
141+ this.expandProp = expandProp;
142+ }
143+
144+ /**
145+ * Reads a policy configuration into the Policy object using a
146+ * Reader object. <p>
147+ *
148+ * @param policy the policy Reader object.
149+ *
150+ * @exception ParsingException if the policy configuration contains
151+ * a syntax error.
152+ *
153+ * @exception IOException if an error occurs while reading the policy
154+ * configuration.
155+ */
156+
157+ public void read(Reader policy)
158+ throws ParsingException, IOException
159+ {
160+ if (!(policy instanceof BufferedReader)) {
161+ policy = new BufferedReader(policy);
162+ }
163+
164+ /**
165+ * Configure the stream tokenizer:
166+ * Recognize strings between "..."
167+ * Don't convert words to lowercase
168+ * Recognize both C-style and C++-style comments
169+ * Treat end-of-line as white space, not as a token
170+ */
171+ st = new StreamTokenizer(policy);
172+
173+ st.resetSyntax();
174+ st.wordChars('a', 'z');
175+ st.wordChars('A', 'Z');
176+ st.wordChars('.', '.');
177+ st.wordChars('0', '9');
178+ st.wordChars('_', '_');
179+ st.wordChars('$', '$');
180+ st.wordChars(128 + 32, 255);
181+ st.whitespaceChars(0, ' ');
182+ st.commentChar('/');
183+ st.quoteChar('\'');
184+ st.quoteChar('"');
185+ st.lowerCaseMode(false);
186+ st.ordinaryChar('/');
187+ st.slashSlashComments(true);
188+ st.slashStarComments(true);
189+
190+ /**
191+ * The main parsing loop. The loop is executed once
192+ * for each entry in the config file. The entries
193+ * are delimited by semicolons. Once we've read in
194+ * the information for an entry, go ahead and try to
195+ * add it to the policy vector.
196+ *
197+ */
198+
199+ lookahead = st.nextToken();
200+ while (lookahead != StreamTokenizer.TT_EOF) {
201+ if (peek("grant")) {
202+ GrantEntry ge = parseGrantEntry();
203+ // could be null if we couldn't expand a property
204+ if (ge != null)
205+ add(ge);
206+ } else if (peek("keystore") && keyStoreUrlString==null) {
207+ // only one keystore entry per policy file, others will be
208+ // ignored
209+ parseKeyStoreEntry();
210+ } else if (peek("keystorePasswordURL") && storePassURL==null) {
211+ // only one keystore passwordURL per policy file, others will be
212+ // ignored
213+ parseStorePassURL();
214+ } else {
215+ // error?
216+ }
217+ match(";");
218+ }
219+
220+ if (keyStoreUrlString == null && storePassURL != null) {
221+ throw new ParsingException(ResourcesMgr.getString
222+ ("keystorePasswordURL.can.not.be.specified.without.also.specifying.keystore"));
223+ }
224+ }
225+
226+ public void add(GrantEntry ge)
227+ {
228+ grantEntries.addElement(ge);
229+ }
230+
231+ public void replace(GrantEntry origGe, GrantEntry newGe)
232+ {
233+ grantEntries.setElementAt(newGe, grantEntries.indexOf(origGe));
234+ }
235+
236+ public boolean remove(GrantEntry ge)
237+ {
238+ return grantEntries.removeElement(ge);
239+ }
240+
241+ /**
242+ * Returns the (possibly expanded) keystore location, or null if the
243+ * expansion fails.
244+ */
245+ public String getKeyStoreUrl() {
246+ try {
247+ if (keyStoreUrlString!=null && keyStoreUrlString.length()!=0) {
248+ return expand(keyStoreUrlString, true).replace
249+ (File.separatorChar, '/');
250+ }
251+ } catch (PropertyExpander.ExpandException peee) {
252+ if (debug != null) {
253+ debug.println(peee.toString());
254+ }
255+ return null;
256+ }
257+ return null;
258+ }
259+
260+ public void setKeyStoreUrl(String url) {
261+ keyStoreUrlString = url;
262+ }
263+
264+ public String getKeyStoreType() {
265+ return keyStoreType;
266+ }
267+
268+ public void setKeyStoreType(String type) {
269+ keyStoreType = type;
270+ }
271+
272+ public String getKeyStoreProvider() {
273+ return keyStoreProvider;
274+ }
275+
276+ public void setKeyStoreProvider(String provider) {
277+ keyStoreProvider = provider;
278+ }
279+
280+ public String getStorePassURL() {
281+ try {
282+ if (storePassURL!=null && storePassURL.length()!=0) {
283+ return expand(storePassURL, true).replace
284+ (File.separatorChar, '/');
285+ }
286+ } catch (PropertyExpander.ExpandException peee) {
287+ if (debug != null) {
288+ debug.println(peee.toString());
289+ }
290+ return null;
291+ }
292+ return null;
293+ }
294+
295+ public void setStorePassURL(String storePassURL) {
296+ this.storePassURL = storePassURL;
297+ }
298+
299+ /**
300+ * Enumerate all the entries in the global policy object.
301+ * This method is used by policy admin tools. The tools
302+ * should use the Enumeration methods on the returned object
303+ * to fetch the elements sequentially.
304+ */
305+ public Enumeration<GrantEntry> grantElements(){
306+ return grantEntries.elements();
307+ }
308+
309+ /**
310+ * write out the policy
311+ */
312+
313+ public void write(Writer policy)
314+ {
315+ PrintWriter out = new PrintWriter(new BufferedWriter(policy));
316+
317+ Enumeration<GrantEntry> enum_ = grantElements();
318+
319+ out.println("/* AUTOMATICALLY GENERATED ON "+
320+ (new java.util.Date()) + "*/");
321+ out.println("/* DO NOT EDIT */");
322+ out.println();
323+
324+ // write the (unexpanded) keystore entry as the first entry of the
325+ // policy file
326+ if (keyStoreUrlString != null) {
327+ writeKeyStoreEntry(out);
328+ }
329+ if (storePassURL != null) {
330+ writeStorePassURL(out);
331+ }
332+
333+ // write "grant" entries
334+ while (enum_.hasMoreElements()) {
335+ GrantEntry ge = enum_.nextElement();
336+ ge.write(out);
337+ out.println();
338+ }
339+ out.flush();
340+ }
341+
342+ /**
343+ * parses a keystore entry
344+ */
345+ private void parseKeyStoreEntry() throws ParsingException, IOException {
346+ match("keystore");
347+ keyStoreUrlString = match("quoted string");
348+
349+ // parse keystore type
350+ if (!peek(",")) {
351+ return; // default type
352+ }
353+ match(",");
354+
355+ if (peek("\"")) {
356+ keyStoreType = match("quoted string");
357+ } else {
358+ throw new ParsingException(st.lineno(),
359+ ResourcesMgr.getString("expected.keystore.type"));
360+ }
361+
362+ // parse keystore provider
363+ if (!peek(",")) {
364+ return; // provider optional
365+ }
366+ match(",");
367+
368+ if (peek("\"")) {
369+ keyStoreProvider = match("quoted string");
370+ } else {
371+ throw new ParsingException(st.lineno(),
372+ ResourcesMgr.getString("expected.keystore.provider"));
373+ }
374+ }
375+
376+ private void parseStorePassURL() throws ParsingException, IOException {
377+ match("keyStorePasswordURL");
378+ storePassURL = match("quoted string");
379+ }
380+
381+ /**
382+ * writes the (unexpanded) keystore entry
383+ */
384+ private void writeKeyStoreEntry(PrintWriter out) {
385+ out.print("keystore \"");
386+ out.print(keyStoreUrlString);
387+ out.print('"');
388+ if (keyStoreType != null && keyStoreType.length() > 0)
389+ out.print(", \"" + keyStoreType + "\"");
390+ if (keyStoreProvider != null && keyStoreProvider.length() > 0)
391+ out.print(", \"" + keyStoreProvider + "\"");
392+ out.println(";");
393+ out.println();
394+ }
395+
396+ private void writeStorePassURL(PrintWriter out) {
397+ out.print("keystorePasswordURL \"");
398+ out.print(storePassURL);
399+ out.print('"');
400+ out.println(";");
401+ out.println();
402+ }
403+
404+ /**
405+ * parse a Grant entry
406+ */
407+ private GrantEntry parseGrantEntry()
408+ throws ParsingException, IOException
409+ {
410+ GrantEntry e = new GrantEntry();
411+ LinkedList<PrincipalEntry> principals = null;
412+ boolean ignoreEntry = false;
413+
414+ match("grant");
415+
416+ while(!peek("{")) {
417+
418+ if (peekAndMatch("Codebase")) {
419+ if (e.codeBase != null)
420+ throw new ParsingException(
421+ st.lineno(),
422+ ResourcesMgr.getString
423+ ("multiple.Codebase.expressions"));
424+ e.codeBase = match("quoted string");
425+ peekAndMatch(",");
426+ } else if (peekAndMatch("SignedBy")) {
427+ if (e.signedBy != null)
428+ throw new ParsingException(
429+ st.lineno(),
430+ ResourcesMgr.getString(
431+ "multiple.SignedBy.expressions"));
432+ e.signedBy = match("quoted string");
433+
434+ // verify syntax of the aliases
435+ StringTokenizer aliases = new StringTokenizer(e.signedBy,
436+ ",", true);
437+ int actr = 0;
438+ int cctr = 0;
439+ while (aliases.hasMoreTokens()) {
440+ String alias = aliases.nextToken().trim();
441+ if (alias.equals(","))
442+ cctr++;
443+ else if (alias.length() > 0)
444+ actr++;
445+ }
446+ if (actr <= cctr)
447+ throw new ParsingException(
448+ st.lineno(),
449+ ResourcesMgr.getString(
450+ "SignedBy.has.empty.alias"));
451+
452+ peekAndMatch(",");
453+ } else if (peekAndMatch("Principal")) {
454+ if (principals == null) {
455+ principals = new LinkedList<PrincipalEntry>();
456+ }
457+
458+ String principalClass;
459+ String principalName;
460+
461+ if (peek("\"")) {
462+ // both the principalClass and principalName
463+ // will be replaced later
464+ principalClass = REPLACE_NAME;
465+ principalName = match("principal type");
466+ } else {
467+ // check for principalClass wildcard
468+ if (peek("*")) {
469+ match("*");
470+ principalClass = PrincipalEntry.WILDCARD_CLASS;
471+ } else {
472+ principalClass = match("principal type");
473+ }
474+
475+ // check for principalName wildcard
476+ if (peek("*")) {
477+ match("*");
478+ principalName = PrincipalEntry.WILDCARD_NAME;
479+ } else {
480+ principalName = match("quoted string");
481+ }
482+
483+ // disallow WILDCARD_CLASS && actual name
484+ if (principalClass.equals(PrincipalEntry.WILDCARD_CLASS) &&
485+ !principalName.equals(PrincipalEntry.WILDCARD_NAME)) {
486+ if (debug != null) {
487+ debug.println("disallowing principal that " +
488+ "has WILDCARD class but no WILDCARD name");
489+ }
490+ throw new ParsingException
491+ (st.lineno(),
492+ ResourcesMgr.getString
493+ ("can.not.specify.Principal.with.a.wildcard.class.without.a.wildcard.name"));
494+ }
495+ }
496+
497+ try {
498+ principalName = expand(principalName);
499+
500+ if (principalClass.equals
501+ ("javax.security.auth.x500.X500Principal") &&
502+ !principalName.equals(PrincipalEntry.WILDCARD_NAME)) {
503+
504+ // 4702543: X500 names with an EmailAddress
505+ // were encoded incorrectly. construct a new
506+ // X500Principal with correct encoding.
507+
508+ X500Principal p = new X500Principal
509+ ((new X500Principal(principalName)).toString());
510+ principalName = p.getName();
511+ }
512+
513+ principals.add
514+ (new PrincipalEntry(principalClass, principalName));
515+ } catch (PropertyExpander.ExpandException peee) {
516+ // ignore the entire policy entry
517+ // but continue parsing all the info
518+ // so we can get to the next entry
519+ if (debug != null) {
520+ debug.println("principal name expansion failed: " +
521+ principalName);
522+ }
523+ ignoreEntry = true;
524+ }
525+ peekAndMatch(",");
526+
527+ } else {
528+ throw new ParsingException(st.lineno(),
529+ ResourcesMgr.getString(
530+ "expected.codeBase.or.SignedBy.or.Principal"));
531+ }
532+ }
533+
534+ if (principals != null) e.principals = principals;
535+ match("{");
536+
537+ while(!peek("}")) {
538+ if (peek("Permission")) {
539+ try {
540+ PermissionEntry pe = parsePermissionEntry();
541+ e.add(pe);
542+ } catch (PropertyExpander.ExpandException peee) {
543+ // ignore. The add never happened
544+ if (debug != null) {
545+ debug.println(peee.toString());
546+ }
547+ skipEntry(); // BugId 4219343
548+ }
549+ match(";");
550+ } else {
551+ throw new
552+ ParsingException(st.lineno(),
553+ ResourcesMgr.getString(
554+ "expected.permission.entry"));
555+ }
556+ }
557+ match("}");
558+
559+ try {
560+ if (e.signedBy != null) e.signedBy = expand(e.signedBy);
561+ if (e.codeBase != null) {
562+
563+ // For backward compatibility with 1.4
564+ if (e.codeBase.equals(OLD_EXTDIRS_EXPANSION)) {
565+ e.codeBase = EXTDIRS_EXPANSION;
566+ }
567+ int es;
568+ if ((es=e.codeBase.indexOf(EXTDIRS_EXPANSION)) < 0) {
569+ e.codeBase = expand(e.codeBase, true).replace
570+ (File.separatorChar, '/');
571+ } else {
572+ // expand the system property "java.ext.dirs",
573+ // parse it into its path components,
574+ // and then create a grant entry for each component
575+ String[] extDirs = parseExtDirs(e.codeBase, es);
576+ if (extDirs != null && extDirs.length > 0) {
577+ for (int i = 0; i < extDirs.length; i++) {
578+ GrantEntry newGe = (GrantEntry)e.clone();
579+ newGe.codeBase = extDirs[i];
580+ add(newGe);
581+
582+ if (debug != null) {
583+ debug.println("creating policy entry for " +
584+ "expanded java.ext.dirs path:\n\t\t" +
585+ extDirs[i]);
586+ }
587+ }
588+ }
589+ ignoreEntry = true;
590+ }
591+ }
592+ } catch (PropertyExpander.ExpandException peee) {
593+ if (debug != null) {
594+ debug.println(peee.toString());
595+ }
596+ return null;
597+ }
598+
599+ return (ignoreEntry == true) ? null : e;
600+ }
601+
602+ /**
603+ * parse a Permission entry
604+ */
605+ private PermissionEntry parsePermissionEntry()
606+ throws ParsingException, IOException, PropertyExpander.ExpandException
607+ {
608+ PermissionEntry e = new PermissionEntry();
609+
610+ // Permission
611+ match("Permission");
612+ e.permission = match("permission type");
613+
614+ if (peek("\"")) {
615+ // Permission name
616+ e.name = expand(match("quoted string"));
617+ }
618+
619+ if (!peek(",")) {
620+ return e;
621+ }
622+ match(",");
623+
624+ if (peek("\"")) {
625+ e.action = expand(match("quoted string"));
626+ if (!peek(",")) {
627+ return e;
628+ }
629+ match(",");
630+ }
631+
632+ if (peekAndMatch("SignedBy")) {
633+ e.signedBy = expand(match("quoted string"));
634+ }
635+ return e;
636+ }
637+
638+ // package-private: used by PolicyFile for static policy
639+ static String[] parseExtDirs(String codebase, int start) {
640+
641+ String s = System.getProperty(EXTDIRS_PROPERTY);
642+ String globalPrefix = (start > 0 ? codebase.substring(0, start) : "file:");
643+ int end = start + EXTDIRS_EXPANSION.length();
644+ String globalSuffix = (end < codebase.length() ? codebase.substring(end) :
645+ (String) null);
646+
647+ String[] dirs = null;
648+ String localSuffix;
649+ if (s != null) {
650+ StringTokenizer st =
651+ new StringTokenizer(s, File.pathSeparator);
652+ int count = st.countTokens();
653+ dirs = new String[count];
654+ for (int i = 0; i < count; i++) {
655+ File file = new File(st.nextToken());
656+ dirs[i] = sun.net.www.ParseUtil.encodePath
657+ (file.getAbsolutePath());
658+
659+ if (!dirs[i].startsWith("/")) {
660+ dirs[i] = "/" + dirs[i];
661+ }
662+
663+ localSuffix = (globalSuffix == null ?
664+ (dirs[i].endsWith("/") ? "*" : "/*") :
665+ globalSuffix);
666+
667+ dirs[i] = globalPrefix + dirs[i] + localSuffix;
668+ }
669+ }
670+ return dirs;
671+ }
672+
673+ private boolean peekAndMatch(String expect)
674+ throws ParsingException, IOException
675+ {
676+ if (peek(expect)) {
677+ match(expect);
678+ return true;
679+ } else {
680+ return false;
681+ }
682+ }
683+
684+ private boolean peek(String expect) {
685+ boolean found = false;
686+
687+ switch (lookahead) {
688+
689+ case StreamTokenizer.TT_WORD:
690+ if (expect.equalsIgnoreCase(st.sval))
691+ found = true;
692+ break;
693+ case ',':
694+ if (expect.equalsIgnoreCase(","))
695+ found = true;
696+ break;
697+ case '{':
698+ if (expect.equalsIgnoreCase("{"))
699+ found = true;
700+ break;
701+ case '}':
702+ if (expect.equalsIgnoreCase("}"))
703+ found = true;
704+ break;
705+ case '"':
706+ if (expect.equalsIgnoreCase("\""))
707+ found = true;
708+ break;
709+ case '*':
710+ if (expect.equalsIgnoreCase("*"))
711+ found = true;
712+ break;
713+ default:
714+
715+ }
716+ return found;
717+ }
718+
719+ private String match(String expect)
720+ throws ParsingException, IOException
721+ {
722+ String value = null;
723+
724+ switch (lookahead) {
725+ case StreamTokenizer.TT_NUMBER:
726+ throw new ParsingException(st.lineno(), expect,
727+ ResourcesMgr.getString("number.") +
728+ String.valueOf(st.nval));
729+ case StreamTokenizer.TT_EOF:
730+ MessageFormat form = new MessageFormat(
731+ ResourcesMgr.getString
732+ ("expected.expect.read.end.of.file."));
733+ Object[] source = {expect};
734+ throw new ParsingException(form.format(source));
735+ case StreamTokenizer.TT_WORD:
736+ if (expect.equalsIgnoreCase(st.sval)) {
737+ lookahead = st.nextToken();
738+ } else if (expect.equalsIgnoreCase("permission type")) {
739+ value = st.sval;
740+ lookahead = st.nextToken();
741+ } else if (expect.equalsIgnoreCase("principal type")) {
742+ value = st.sval;
743+ lookahead = st.nextToken();
744+ } else {
745+ throw new ParsingException(st.lineno(), expect,
746+ st.sval);
747+ }
748+ break;
749+ case '"':
750+ if (expect.equalsIgnoreCase("quoted string")) {
751+ value = st.sval;
752+ lookahead = st.nextToken();
753+ } else if (expect.equalsIgnoreCase("permission type")) {
754+ value = st.sval;
755+ lookahead = st.nextToken();
756+ } else if (expect.equalsIgnoreCase("principal type")) {
757+ value = st.sval;
758+ lookahead = st.nextToken();
759+ } else {
760+ throw new ParsingException(st.lineno(), expect, st.sval);
761+ }
762+ break;
763+ case ',':
764+ if (expect.equalsIgnoreCase(","))
765+ lookahead = st.nextToken();
766+ else
767+ throw new ParsingException(st.lineno(), expect, ",");
768+ break;
769+ case '{':
770+ if (expect.equalsIgnoreCase("{"))
771+ lookahead = st.nextToken();
772+ else
773+ throw new ParsingException(st.lineno(), expect, "{");
774+ break;
775+ case '}':
776+ if (expect.equalsIgnoreCase("}"))
777+ lookahead = st.nextToken();
778+ else
779+ throw new ParsingException(st.lineno(), expect, "}");
780+ break;
781+ case ';':
782+ if (expect.equalsIgnoreCase(";"))
783+ lookahead = st.nextToken();
784+ else
785+ throw new ParsingException(st.lineno(), expect, ";");
786+ break;
787+ case '*':
788+ if (expect.equalsIgnoreCase("*"))
789+ lookahead = st.nextToken();
790+ else
791+ throw new ParsingException(st.lineno(), expect, "*");
792+ break;
793+ default:
794+ throw new ParsingException(st.lineno(), expect,
795+ new String(new char[] {(char)lookahead}));
796+ }
797+ return value;
798+ }
799+
800+ /**
801+ * skip all tokens for this entry leaving the delimiter ";"
802+ * in the stream.
803+ */
804+ private void skipEntry() throws ParsingException, IOException {
805+ while(lookahead != ';') {
806+ switch (lookahead) {
807+ case StreamTokenizer.TT_NUMBER:
808+ throw new ParsingException(st.lineno(), ";",
809+ ResourcesMgr.getString("number.") +
810+ String.valueOf(st.nval));
811+ case StreamTokenizer.TT_EOF:
812+ throw new ParsingException(ResourcesMgr.getString
813+ ("expected.read.end.of.file."));
814+ default:
815+ lookahead = st.nextToken();
816+ }
817+ }
818+ }
819+
820+ /**
821+ * Each grant entry in the policy configuration file is
822+ * represented by a
823+ * GrantEntry object. <p>
824+ *
825+ * <p>
826+ * For example, the entry
827+ * <pre>
828+ * grant signedBy "Duke" {
829+ * permission java.io.FilePermission "/tmp", "read,write";
830+ * };
831+ *
832+ * </pre>
833+ * is represented internally
834+ * <pre>
835+ *
836+ * pe = new PermissionEntry("java.io.FilePermission",
837+ * "/tmp", "read,write");
838+ *
839+ * ge = new GrantEntry("Duke", null);
840+ *
841+ * ge.add(pe);
842+ *
843+ * </pre>
844+ *
845+ * @author Roland Schemers
846+ *
847+ * version 1.19, 05/21/98
848+ */
849+
850+ public static class GrantEntry {
851+
852+ public String signedBy;
853+ public String codeBase;
854+ public LinkedList<PrincipalEntry> principals;
855+ public Vector<PermissionEntry> permissionEntries;
856+
857+ public GrantEntry() {
858+ principals = new LinkedList<PrincipalEntry>();
859+ permissionEntries = new Vector<PermissionEntry>();
860+ }
861+
862+ public GrantEntry(String signedBy, String codeBase) {
863+ this.codeBase = codeBase;
864+ this.signedBy = signedBy;
865+ principals = new LinkedList<PrincipalEntry>();
866+ permissionEntries = new Vector<PermissionEntry>();
867+ }
868+
869+ public void add(PermissionEntry pe)
870+ {
871+ permissionEntries.addElement(pe);
872+ }
873+
874+ public boolean remove(PrincipalEntry pe)
875+ {
876+ return principals.remove(pe);
877+ }
878+
879+ public boolean remove(PermissionEntry pe)
880+ {
881+ return permissionEntries.removeElement(pe);
882+ }
883+
884+ public boolean contains(PrincipalEntry pe)
885+ {
886+ return principals.contains(pe);
887+ }
888+
889+ public boolean contains(PermissionEntry pe)
890+ {
891+ return permissionEntries.contains(pe);
892+ }
893+
894+ /**
895+ * Enumerate all the permission entries in this GrantEntry.
896+ */
897+ public Enumeration<PermissionEntry> permissionElements(){
898+ return permissionEntries.elements();
899+ }
900+
901+
902+ public void write(PrintWriter out) {
903+ out.print("grant");
904+ if (signedBy != null) {
905+ out.print(" signedBy \"");
906+ out.print(signedBy);
907+ out.print('"');
908+ if (codeBase != null)
909+ out.print(", ");
910+ }
911+ if (codeBase != null) {
912+ out.print(" codeBase \"");
913+ out.print(codeBase);
914+ out.print('"');
915+ if (principals != null && principals.size() > 0)
916+ out.print(",\n");
917+ }
918+ if (principals != null && principals.size() > 0) {
919+ ListIterator<PrincipalEntry> pli = principals.listIterator();
920+ while (pli.hasNext()) {
921+ out.print(" ");
922+ PrincipalEntry pe = pli.next();
923+ pe.write(out);
924+ if (pli.hasNext())
925+ out.print(",\n");
926+ }
927+ }
928+ out.println(" {");
929+ Enumeration<PermissionEntry> enum_ = permissionEntries.elements();
930+ while (enum_.hasMoreElements()) {
931+ PermissionEntry pe = enum_.nextElement();
932+ out.write(" ");
933+ pe.write(out);
934+ }
935+ out.println("};");
936+ }
937+
938+ public Object clone() {
939+ GrantEntry ge = new GrantEntry();
940+ ge.codeBase = this.codeBase;
941+ ge.signedBy = this.signedBy;
942+ ge.principals = new LinkedList<PrincipalEntry>(this.principals);
943+ ge.permissionEntries =
944+ new Vector<PermissionEntry>(this.permissionEntries);
945+ return ge;
946+ }
947+ }
948+
949+ /**
950+ * Principal info (class and name) in a grant entry
951+ */
952+ public static class PrincipalEntry {
953+
954+ public static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS";
955+ public static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME";
956+
957+ String principalClass;
958+ String principalName;
959+
960+ /**
961+ * A PrincipalEntry consists of the <code>Principal</code>
962+ * class and <code>Principal</code> name.
963+ *
964+ * <p>
965+ *
966+ * @param principalClass the <code>Principal</code> class. <p>
967+ *
968+ * @param principalName the <code>Principal</code> name. <p>
969+ */
970+ public PrincipalEntry(String principalClass, String principalName) {
971+ if (principalClass == null || principalName == null)
972+ throw new NullPointerException(ResourcesMgr.getString(
973+ "null.principalClass.or.principalName"));
974+ this.principalClass = principalClass;
975+ this.principalName = principalName;
976+ }
977+
978+ public String getPrincipalClass() {
979+ return principalClass;
980+ }
981+
982+ public String getPrincipalName() {
983+ return principalName;
984+ }
985+
986+ public String getDisplayClass() {
987+ if (principalClass.equals(WILDCARD_CLASS)) {
988+ return "*";
989+ } else if (principalClass.equals(REPLACE_NAME)) {
990+ return "";
991+ }
992+ else return principalClass;
993+ }
994+
995+ public String getDisplayName() {
996+ return getDisplayName(false);
997+ }
998+
999+ public String getDisplayName(boolean addQuote) {
1000+ if (principalName.equals(WILDCARD_NAME)) {
1001+ return "*";
1002+ }
1003+ else {
1004+ if (addQuote) return "\"" + principalName + "\"";
1005+ else return principalName;
1006+ }
1007+ }
1008+
1009+ public String toString() {
1010+ if (!principalClass.equals(REPLACE_NAME)) {
1011+ return getDisplayClass() + "/" + getDisplayName();
1012+ } else {
1013+ return getDisplayName();
1014+ }
1015+ }
1016+
1017+ /**
1018+ * Test for equality between the specified object and this object.
1019+ * Two PrincipalEntries are equal if their PrincipalClass and
1020+ * PrincipalName values are equal.
1021+ *
1022+ * <p>
1023+ *
1024+ * @param obj the object to test for equality with this object.
1025+ *
1026+ * @return true if the objects are equal, false otherwise.
1027+ */
1028+ public boolean equals(Object obj) {
1029+ if (this == obj)
1030+ return true;
1031+
1032+ if (!(obj instanceof PrincipalEntry))
1033+ return false;
1034+
1035+ PrincipalEntry that = (PrincipalEntry)obj;
1036+ if (this.principalClass.equals(that.principalClass) &&
1037+ this.principalName.equals(that.principalName)) {
1038+ return true;
1039+ }
1040+
1041+ return false;
1042+ }
1043+
1044+ /**
1045+ * Return a hashcode for this <code>PrincipalEntry</code>.
1046+ *
1047+ * <p>
1048+ *
1049+ * @return a hashcode for this <code>PrincipalEntry</code>.
1050+ */
1051+ public int hashCode() {
1052+ return principalClass.hashCode();
1053+ }
1054+ public void write(PrintWriter out) {
1055+ out.print("principal " + getDisplayClass() + " " +
1056+ getDisplayName(true));
1057+ }
1058+ }
1059+
1060+ /**
1061+ * Each permission entry in the policy configuration file is
1062+ * represented by a
1063+ * PermissionEntry object. <p>
1064+ *
1065+ * <p>
1066+ * For example, the entry
1067+ * <pre>
1068+ * permission java.io.FilePermission "/tmp", "read,write";
1069+ * </pre>
1070+ * is represented internally
1071+ * <pre>
1072+ *
1073+ * pe = new PermissionEntry("java.io.FilePermission",
1074+ * "/tmp", "read,write");
1075+ * </pre>
1076+ *
1077+ * @author Roland Schemers
1078+ *
1079+ * version 1.19, 05/21/98
1080+ */
1081+
1082+ public static class PermissionEntry {
1083+
1084+ public String permission;
1085+ public String name;
1086+ public String action;
1087+ public String signedBy;
1088+
1089+ public PermissionEntry() {
1090+ }
1091+
1092+ public PermissionEntry(String permission,
1093+ String name,
1094+ String action) {
1095+ this.permission = permission;
1096+ this.name = name;
1097+ this.action = action;
1098+ }
1099+
1100+ /**
1101+ * Calculates a hash code value for the object. Objects
1102+ * which are equal will also have the same hashcode.
1103+ */
1104+ public int hashCode() {
1105+ int retval = permission.hashCode();
1106+ if (name != null) retval ^= name.hashCode();
1107+ if (action != null) retval ^= action.hashCode();
1108+ return retval;
1109+ }
1110+
1111+ public boolean equals(Object obj) {
1112+ if (obj == this)
1113+ return true;
1114+
1115+ if (! (obj instanceof PermissionEntry))
1116+ return false;
1117+
1118+ PermissionEntry that = (PermissionEntry) obj;
1119+
1120+ if (this.permission == null) {
1121+ if (that.permission != null) return false;
1122+ } else {
1123+ if (!this.permission.equals(that.permission)) return false;
1124+ }
1125+
1126+ if (this.name == null) {
1127+ if (that.name != null) return false;
1128+ } else {
1129+ if (!this.name.equals(that.name)) return false;
1130+ }
1131+
1132+ if (this.action == null) {
1133+ if (that.action != null) return false;
1134+ } else {
1135+ if (!this.action.equals(that.action)) return false;
1136+ }
1137+
1138+ if (this.signedBy == null) {
1139+ if (that.signedBy != null) return false;
1140+ } else {
1141+ if (!this.signedBy.equals(that.signedBy)) return false;
1142+ }
1143+
1144+ // everything matched -- the 2 objects are equal
1145+ return true;
1146+ }
1147+
1148+ public void write(PrintWriter out) {
1149+ out.print("permission ");
1150+ out.print(permission);
1151+ if (name != null) {
1152+ out.print(" \"");
1153+
1154+ // ATTENTION: regex with double escaping,
1155+ // the normal forms look like:
1156+ // $name =~ s/\\/\\\\/g; and
1157+ // $name =~ s/\"/\\\"/g;
1158+ // and then in a java string, it's escaped again
1159+
1160+ out.print(name.replaceAll("\\\\", "\\\\\\\\").replaceAll("\\\"", "\\\\\\\""));
1161+ out.print('"');
1162+ }
1163+ if (action != null) {
1164+ out.print(", \"");
1165+ out.print(action);
1166+ out.print('"');
1167+ }
1168+ if (signedBy != null) {
1169+ out.print(", signedBy \"");
1170+ out.print(signedBy);
1171+ out.print('"');
1172+ }
1173+ out.println(";");
1174+ }
1175+ }
1176+
1177+ public static class ParsingException extends GeneralSecurityException {
1178+
1179+ private static final long serialVersionUID = -4330692689482574072L;
1180+
1181+ private String i18nMessage;
1182+
1183+ /**
1184+ * Constructs a ParsingException with the specified
1185+ * detail message. A detail message is a String that describes
1186+ * this particular exception, which may, for example, specify which
1187+ * algorithm is not available.
1188+ *
1189+ * @param msg the detail message.
1190+ */
1191+ public ParsingException(String msg) {
1192+ super(msg);
1193+ i18nMessage = msg;
1194+ }
1195+
1196+ public ParsingException(int line, String msg) {
1197+ super("line " + line + ": " + msg);
1198+ MessageFormat form = new MessageFormat
1199+ (ResourcesMgr.getString("line.number.msg"));
1200+ Object[] source = {new Integer(line), msg};
1201+ i18nMessage = form.format(source);
1202+ }
1203+
1204+ public ParsingException(int line, String expect, String actual) {
1205+ super("line " + line + ": expected [" + expect +
1206+ "], found [" + actual + "]");
1207+ MessageFormat form = new MessageFormat(ResourcesMgr.getString
1208+ ("line.number.expected.expect.found.actual."));
1209+ Object[] source = {new Integer(line), expect, actual};
1210+ i18nMessage = form.format(source);
1211+ }
1212+
1213+ public String getLocalizedMessage() {
1214+ return i18nMessage;
1215+ }
1216+ }
1217+
1218+ public static void main(String arg[]) throws Exception {
1219+ FileReader fr = null;
1220+ FileWriter fw = null;
1221+ try {
1222+ PolicyParser pp = new PolicyParser(true);
1223+ fr = new FileReader(arg[0]);
1224+ pp.read(fr);
1225+ fw = new FileWriter(arg[1]);
1226+ pp.write(fw);
1227+ } finally {
1228+ if (fr != null) {
1229+ fr.close();
1230+ }
1231+
1232+ if (fw != null) {
1233+ fw.close();
1234+ }
1235+ }
1236+ }
1237+}