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
26package sun.security.provider;
27
28import java.io.*;
29import java.lang.RuntimePermission;
30import java.net.SocketPermission;
31import java.net.URL;
32import java.util.Enumeration;
33import java.util.Hashtable;
34import java.util.LinkedList;
35import java.util.ListIterator;
36import java.util.Vector;
37import java.util.StringTokenizer;
38import java.text.MessageFormat;
39import javax.security.auth.x500.X500Principal;
40
41import java.security.GeneralSecurityException;
42import sun.security.util.Debug;
43import sun.security.util.PropertyExpander;
44import 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
88public 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}