0001: /*
0002: * @(#)PolicyParser.java 1.33 06/10/11
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: *
0026: */
0027:
0028: package sun.security.provider;
0029:
0030: import java.io.*;
0031: import java.lang.RuntimePermission;
0032: import java.util.Enumeration;
0033: import java.util.LinkedList;
0034: import java.util.ListIterator;
0035: import java.util.Vector;
0036: import java.util.StringTokenizer;
0037: import java.text.MessageFormat; /*
0038: * Initial CDC port; X500Principal exists in
0039: * CDC/FP and is used here only to re-write in
0040: * incorrectly encoded name as part of a bug
0041: * fix, so comment it out for the time being.
0042: import javax.security.auth.x500.X500Principal;
0043: */
0044:
0045: import java.security.GeneralSecurityException;
0046: import sun.security.util.Debug;
0047: import sun.security.util.PropertyExpander;
0048:
0049: /*
0050: * Comment out ResourcesMgr use for the time
0051: * being; it is created now in CDC/FP.
0052: import sun.security.util.ResourcesMgr;
0053: */
0054:
0055: /**
0056: * The policy for a Java runtime (specifying
0057: * which permissions are available for code from various principals)
0058: * is represented as a separate
0059: * persistent configuration. The configuration may be stored as a
0060: * flat ASCII file, as a serialized binary file of
0061: * the Policy class, or as a database. <p>
0062: *
0063: * <p>The Java runtime creates one global Policy object, which is used to
0064: * represent the static policy configuration file. It is consulted by
0065: * a ProtectionDomain when the protection domain initializes its set of
0066: * permissions. <p>
0067: *
0068: * <p>The Policy <code>init</code> method parses the policy
0069: * configuration file, and then
0070: * populates the Policy object. The Policy object is agnostic in that
0071: * it is not involved in making policy decisions. It is merely the
0072: * Java runtime representation of the persistent policy configuration
0073: * file. <p>
0074: *
0075: * <p>When a protection domain needs to initialize its set of
0076: * permissions, it executes code such as the following
0077: * to ask the global Policy object to populate a
0078: * Permissions object with the appropriate permissions:
0079: * <pre>
0080: * policy = Policy.getPolicy();
0081: * Permissions perms = policy.getPermissions(protectiondomain)
0082: * </pre>
0083: *
0084: * <p>The protection domain contains CodeSource
0085: * object, which encapsulates its codebase (URL) and public key attributes.
0086: * It also contains the principals associated with the domain.
0087: * The Policy object evaluates the global policy in light of who the
0088: * principal is and what the code source is and returns an appropriate
0089: * Permissions object.
0090: *
0091: * @version 1.28, 01/14/00
0092: * @author Roland Schemers
0093: * @author Ram Marti
0094: *
0095: * @since JDK1.2
0096: */
0097:
0098: public class PolicyParser {
0099:
0100: // needs to be public for PolicyTool
0101: public static final String REPLACE_NAME = "PolicyParser.REPLACE_NAME";
0102:
0103: private Vector grantEntries;
0104:
0105: // Convenience variables for parsing
0106: private static final Debug debug = Debug.getInstance("parser",
0107: "\t[Policy Parser]");
0108: private StreamTokenizer st;
0109: private int lookahead;
0110: private int linenum;
0111: private boolean expandProp = false;
0112: private String keyStoreUrlString = null; // unexpanded
0113: private String keyStoreType = null;
0114:
0115: private String expand(String value)
0116: throws PropertyExpander.ExpandException {
0117: return expand(value, false);
0118: }
0119:
0120: private String expand(String value, boolean encodeURL)
0121: throws PropertyExpander.ExpandException {
0122: if (!expandProp) {
0123: return value;
0124: } else {
0125: return PropertyExpander.expand(value, encodeURL);
0126: }
0127: }
0128:
0129: /**
0130: * Creates a PolicyParser object.
0131: */
0132:
0133: public PolicyParser() {
0134: grantEntries = new Vector();
0135: }
0136:
0137: public PolicyParser(boolean expandProp) {
0138: this ();
0139: this .expandProp = expandProp;
0140: }
0141:
0142: /**
0143: * Reads a policy configuration into the Policy object using a
0144: * Reader object. <p>
0145: *
0146: * @param policy the policy Reader object.
0147: *
0148: * @exception ParsingException if the policy configuration contains
0149: * a syntax error.
0150: *
0151: * @exception IOException if an error occurs while reading the policy
0152: * configuration.
0153: */
0154:
0155: public void read(Reader policy) throws ParsingException,
0156: IOException {
0157: if (!(policy instanceof BufferedReader)) {
0158: policy = new BufferedReader(policy);
0159: }
0160:
0161: /**
0162: * Configure the stream tokenizer:
0163: * Recognize strings between "..."
0164: * Don't convert words to lowercase
0165: * Recognize both C-style and C++-style comments
0166: * Treat end-of-line as white space, not as a token
0167: */
0168: st = new StreamTokenizer(policy);
0169:
0170: st.resetSyntax();
0171: st.wordChars('a', 'z');
0172: st.wordChars('A', 'Z');
0173: st.wordChars('.', '.');
0174: st.wordChars('0', '9');
0175: st.wordChars('_', '_');
0176: st.wordChars('$', '$');
0177: st.wordChars(128 + 32, 255);
0178: st.whitespaceChars(0, ' ');
0179: st.commentChar('/');
0180: st.quoteChar('\'');
0181: st.quoteChar('"');
0182: st.lowerCaseMode(false);
0183: st.ordinaryChar('/');
0184: st.slashSlashComments(true);
0185: st.slashStarComments(true);
0186:
0187: /**
0188: * The main parsing loop. The loop is executed once
0189: * for each entry in the config file. The entries
0190: * are delimited by semicolons. Once we've read in
0191: * the information for an entry, go ahead and try to
0192: * add it to the policy vector.
0193: *
0194: */
0195:
0196: lookahead = st.nextToken();
0197: while (lookahead != StreamTokenizer.TT_EOF) {
0198: if (peek("grant")) {
0199: GrantEntry ge = parseGrantEntry();
0200: // could be null if we couldn't expand a property
0201: if (ge != null)
0202: add(ge);
0203: } else if (peek("keystore") && keyStoreUrlString == null) {
0204: // only one keystore entry per policy file, others will be
0205: // ignored
0206: parseKeyStoreEntry();
0207: } else {
0208: // error?
0209: }
0210: match(";");
0211: }
0212: }
0213:
0214: public void add(GrantEntry ge) {
0215: grantEntries.addElement(ge);
0216: }
0217:
0218: public void replace(GrantEntry origGe, GrantEntry newGe) {
0219: grantEntries.setElementAt(newGe, grantEntries.indexOf(origGe));
0220: }
0221:
0222: public boolean remove(GrantEntry ge) {
0223: return grantEntries.removeElement(ge);
0224: }
0225:
0226: /**
0227: * Returns the (possibly expanded) keystore location, or null if the
0228: * expansion fails.
0229: */
0230: public String getKeyStoreUrl() {
0231: try {
0232: if (keyStoreUrlString != null
0233: && keyStoreUrlString.length() != 0) {
0234: return expand(keyStoreUrlString, true).replace(
0235: File.separatorChar, '/');
0236: }
0237: } catch (PropertyExpander.ExpandException peee) {
0238: if (debug != null) {
0239: debug.println(peee.toString());
0240: }
0241: return null;
0242: }
0243: return null;
0244: }
0245:
0246: public void setKeyStoreUrl(String url) {
0247: keyStoreUrlString = url;
0248: }
0249:
0250: public String getKeyStoreType() {
0251: return keyStoreType;
0252: }
0253:
0254: public void setKeyStoreType(String type) {
0255: keyStoreType = type;
0256: }
0257:
0258: /**
0259: * Enumerate all the entries in the global policy object.
0260: * This method is used by policy admin tools. The tools
0261: * should use the Enumeration methods on the returned object
0262: * to fetch the elements sequentially.
0263: */
0264: public Enumeration grantElements() {
0265: return grantEntries.elements();
0266: }
0267:
0268: /**
0269: * write out the policy
0270: */
0271:
0272: public void write(Writer policy) {
0273: PrintWriter out = new PrintWriter(new BufferedWriter(policy));
0274:
0275: Enumeration enum_ = grantElements();
0276:
0277: out.println("/* AUTOMATICALLY GENERATED ON "
0278: + (new java.util.Date()) + "*/");
0279: out.println("/* DO NOT EDIT */");
0280: out.println();
0281:
0282: // write the (unexpanded) keystore entry as the first entry of the
0283: // policy file
0284: if (keyStoreUrlString != null) {
0285: writeKeyStoreEntry(out);
0286: }
0287:
0288: // write "grant" entries
0289: while (enum_.hasMoreElements()) {
0290: GrantEntry ge = (GrantEntry) enum_.nextElement();
0291: ge.write(out);
0292: out.println();
0293: }
0294: out.flush();
0295: }
0296:
0297: /**
0298: * parses a keystore entry
0299: */
0300: private void parseKeyStoreEntry() throws ParsingException,
0301: IOException {
0302: match("keystore");
0303: keyStoreUrlString = match("quoted string");
0304:
0305: // parse keystore type
0306: if (!peek(",")) {
0307: return; // default type
0308: }
0309: match(",");
0310:
0311: if (peek("\"")) {
0312: keyStoreType = match("quoted string");
0313: } else {
0314: /* Comment out ResourcesMgr use during initial
0315: * CDC port.
0316: throw new ParsingException(st.lineno(),
0317: ResourcesMgr.getString("expected keystore type"));
0318: */
0319: throw new ParsingException(st.lineno(),
0320: "expected keystore type");
0321: }
0322: }
0323:
0324: /**
0325: * writes the (unexpanded) keystore entry
0326: */
0327: private void writeKeyStoreEntry(PrintWriter out) {
0328: out.print("keystore \"");
0329: out.print(keyStoreUrlString);
0330: out.print('"');
0331: if (keyStoreType != null && keyStoreType.length() > 0)
0332: out.print(", \"" + keyStoreType + "\"");
0333: out.println(";");
0334: out.println();
0335: }
0336:
0337: /**
0338: * parse a Grant entry
0339: */
0340: private GrantEntry parseGrantEntry() throws ParsingException,
0341: IOException {
0342: GrantEntry e = new GrantEntry();
0343: LinkedList principals = null;
0344: boolean ignoreEntry = false;
0345:
0346: match("grant");
0347:
0348: while (!peek("{")) {
0349:
0350: if (peekAndMatch("Codebase")) {
0351: if (e.codeBase != null)
0352: /* comment out ResourceMgr use
0353: * in initial CDC port.
0354: throw new ParsingException(
0355: st.lineno(),
0356: ResourcesMgr.getString
0357: ("multiple Codebase expressions"));
0358: */
0359: throw new ParsingException(st.lineno(),
0360: "multiple Codebase expressions");
0361: e.codeBase = match("quoted string");
0362: peekAndMatch(",");
0363: } else if (peekAndMatch("SignedBy")) {
0364: if (e.signedBy != null)
0365: /* Comment out ResourcesMgr use in
0366: * initial CDC port.
0367: throw new ParsingException(
0368: st.lineno(),
0369: ResourcesMgr.getString(
0370: "multiple SignedBy expressions"));
0371: */
0372: throw new ParsingException(st.lineno(),
0373: "multiple SignedBy expressions");
0374: e.signedBy = match("quoted string");
0375:
0376: // verify syntax of the aliases
0377: StringTokenizer aliases = new StringTokenizer(
0378: e.signedBy, ",", true);
0379: int actr = 0;
0380: int cctr = 0;
0381: while (aliases.hasMoreTokens()) {
0382: String alias = aliases.nextToken().trim();
0383: if (alias.equals(","))
0384: cctr++;
0385: else if (alias.length() > 0)
0386: actr++;
0387: }
0388: if (actr <= cctr)
0389: /* Comment out ResourcesMgr use in
0390: * initial CDC port.
0391: throw new ParsingException(
0392: st.lineno(),
0393: ResourcesMgr.getString(
0394: "SignedBy has empty alias"));
0395: */
0396: throw new ParsingException(st.lineno(),
0397: "SignedBy has empty alias");
0398:
0399: peekAndMatch(",");
0400: } else if (peekAndMatch("Principal")) {
0401: if (principals == null) {
0402: principals = new LinkedList();
0403: }
0404:
0405: String principalClass;
0406: String principalName;
0407:
0408: if (peek("\"")) {
0409: // both the principalClass and principalName
0410: // will be replaced later
0411: principalClass = REPLACE_NAME;
0412: principalName = match("principal type");
0413: } else {
0414: // check for principalClass wildcard
0415: if (peek("*")) {
0416: match("*");
0417: principalClass = PrincipalEntry.WILDCARD_CLASS;
0418: } else {
0419: principalClass = match("principal type");
0420: }
0421:
0422: // check for principalName wildcard
0423: if (peek("*")) {
0424: match("*");
0425: principalName = PrincipalEntry.WILDCARD_NAME;
0426: } else {
0427: principalName = match("quoted string");
0428: }
0429:
0430: // disallow WILDCARD_CLASS && actual name
0431: if (principalClass
0432: .equals(PrincipalEntry.WILDCARD_CLASS)
0433: && !principalName
0434: .equals(PrincipalEntry.WILDCARD_NAME)) {
0435: if (debug != null) {
0436: debug
0437: .println("disallowing principal that "
0438: + "has WILDCARD class but no WILDCARD name");
0439: }
0440: /* Comment out ResourcesMgr use in
0441: * initial CDC port.
0442: throw new ParsingException
0443: (st.lineno(),
0444: ResourcesMgr.getString
0445: ("can not specify Principal with a " +
0446: "wildcard class without a wildcard name"));
0447: */
0448: throw new ParsingException(
0449: st.lineno(),
0450: "can not specify Principal with a "
0451: + "wildcard class without a wildcard name");
0452: }
0453: }
0454:
0455: try {
0456: principalName = expand(principalName);
0457:
0458: /* See earlier comment. X500Principal
0459: * exists in CDC/FP but not currently in
0460: * CDC. Comment out this utilization for
0461: * the time being.
0462: if (principalClass.equals
0463: ("javax.security.auth.x500.X500Principal") &&
0464: !principalName.equals(PrincipalEntry.WILDCARD_NAME)) {
0465:
0466: // 4702543: X500 names with an EmailAddress
0467: // were encoded incorrectly. construct a new
0468: // X500Principal with correct encoding.
0469:
0470: X500Principal p = new X500Principal
0471: ((new X500Principal(principalName)).toString());
0472: principalName = p.getName();
0473: }
0474: */
0475:
0476: principals.add(new PrincipalEntry(principalClass,
0477: principalName));
0478: } catch (PropertyExpander.ExpandException peee) {
0479: // ignore the entire policy entry
0480: // but continue parsing all the info
0481: // so we can get to the next entry
0482: if (debug != null) {
0483: debug
0484: .println("principal name expansion failed: "
0485: + principalName);
0486: }
0487: ignoreEntry = true;
0488: }
0489: peekAndMatch(",");
0490:
0491: } else {
0492: /* Comment out ResourcesMgr use in
0493: * initial CDC port.
0494: throw new ParsingException(st.lineno(),
0495: ResourcesMgr.getString(
0496: "expected codeBase or SignedBy or " +
0497: "Principal"));
0498: */
0499: throw new ParsingException(st.lineno(),
0500: "expected codeBase or SignedBy or "
0501: + "Principal");
0502: }
0503: }
0504:
0505: if (principals != null)
0506: e.principals = principals;
0507: match("{");
0508:
0509: while (!peek("}")) {
0510: if (peek("Permission")) {
0511: try {
0512: PermissionEntry pe = parsePermissionEntry();
0513: e.add(pe);
0514: } catch (PropertyExpander.ExpandException peee) {
0515: // ignore. The add never happened
0516: if (debug != null) {
0517: debug.println(peee.toString());
0518: }
0519: skipEntry(); // BugId 4219343
0520: }
0521: match(";");
0522: } else {
0523: throw new
0524: /* Comment out ResourcesMgr use in
0525: * initial CDC port.
0526: ParsingException(st.lineno(),
0527: ResourcesMgr.getString(
0528: "expected permission entry"));
0529: */
0530: ParsingException(st.lineno(),
0531: "expected permission entry");
0532: }
0533: }
0534: match("}");
0535:
0536: try {
0537: if (e.signedBy != null)
0538: e.signedBy = expand(e.signedBy);
0539: if (e.codeBase != null) {
0540: if (!e.codeBase.equals("${java.ext.dirs}")) {
0541: e.codeBase = expand(e.codeBase, true).replace(
0542: File.separatorChar, '/');
0543: } else {
0544: // expand the system property "java.ext.dirs",
0545: // parse it into its path components,
0546: // and then create a grant entry for each component
0547: String[] extDirs = parseExtDirs();
0548: if (extDirs != null && extDirs.length > 0) {
0549: for (int i = 0; i < extDirs.length; i++) {
0550: GrantEntry newGe = (GrantEntry) e.clone();
0551: newGe.codeBase = extDirs[i];
0552: add(newGe);
0553:
0554: if (debug != null) {
0555: debug
0556: .println("creating policy entry for "
0557: + "expanded java.ext.dirs path:\n\t\t"
0558: + extDirs[i]);
0559: }
0560: }
0561: }
0562: ignoreEntry = true;
0563: }
0564: }
0565: } catch (PropertyExpander.ExpandException peee) {
0566: if (debug != null) {
0567: debug.println(peee.toString());
0568: }
0569: return null;
0570: }
0571:
0572: return (ignoreEntry == true) ? null : e;
0573: }
0574:
0575: /**
0576: * parse a Permission entry
0577: */
0578: private PermissionEntry parsePermissionEntry()
0579: throws ParsingException, IOException,
0580: PropertyExpander.ExpandException {
0581: PermissionEntry e = new PermissionEntry();
0582:
0583: // Permission
0584: match("Permission");
0585: e.permission = match("permission type");
0586:
0587: if (peek("\"")) {
0588: // Permission name
0589: e.name = expand(match("quoted string"));
0590: }
0591:
0592: if (!peek(",")) {
0593: return e;
0594: }
0595: match(",");
0596:
0597: if (peek("\"")) {
0598: e.action = expand(match("quoted string"));
0599: if (!peek(",")) {
0600: return e;
0601: }
0602: match(",");
0603: }
0604:
0605: if (peekAndMatch("SignedBy")) {
0606: e.signedBy = expand(match("quoted string"));
0607: }
0608: return e;
0609: }
0610:
0611: private String[] parseExtDirs() {
0612:
0613: String s = System.getProperty("java.ext.dirs");
0614: String[] dirs = null;
0615: if (s != null) {
0616: StringTokenizer st = new StringTokenizer(s,
0617: File.pathSeparator);
0618: int count = st.countTokens();
0619: dirs = new String[count];
0620: for (int i = 0; i < count; i++) {
0621: File file = new File(st.nextToken());
0622: dirs[i] = sun.net.www.ParseUtil.encodePath(file
0623: .getAbsolutePath());
0624:
0625: if (!dirs[i].startsWith("/")) {
0626: dirs[i] = "/" + dirs[i];
0627: }
0628:
0629: if (dirs[i].endsWith("/")) {
0630: dirs[i] = "file:" + dirs[i] + "*";
0631: } else {
0632: dirs[i] = "file:" + dirs[i] + "/*";
0633: }
0634: }
0635: }
0636: return dirs;
0637: }
0638:
0639: private boolean peekAndMatch(String expect)
0640: throws ParsingException, IOException {
0641: if (peek(expect)) {
0642: match(expect);
0643: return true;
0644: } else {
0645: return false;
0646: }
0647: }
0648:
0649: private boolean peek(String expect) {
0650: boolean found = false;
0651:
0652: switch (lookahead) {
0653:
0654: case StreamTokenizer.TT_WORD:
0655: if (expect.equalsIgnoreCase(st.sval))
0656: found = true;
0657: break;
0658: case ',':
0659: if (expect.equalsIgnoreCase(","))
0660: found = true;
0661: break;
0662: case '{':
0663: if (expect.equalsIgnoreCase("{"))
0664: found = true;
0665: break;
0666: case '}':
0667: if (expect.equalsIgnoreCase("}"))
0668: found = true;
0669: break;
0670: case '"':
0671: if (expect.equalsIgnoreCase("\""))
0672: found = true;
0673: break;
0674: case '*':
0675: if (expect.equalsIgnoreCase("*"))
0676: found = true;
0677: break;
0678: default:
0679:
0680: }
0681: return found;
0682: }
0683:
0684: private String match(String expect) throws ParsingException,
0685: IOException {
0686: String value = null;
0687:
0688: switch (lookahead) {
0689: case StreamTokenizer.TT_NUMBER:
0690: /* Comment out ResourcesMgr use in
0691: * initial CDC port.
0692: throw new ParsingException(st.lineno(), expect,
0693: ResourcesMgr.getString("number ") +
0694: String.valueOf(st.nval));
0695: */
0696: throw new ParsingException(st.lineno(), expect, "number "
0697: + String.valueOf(st.nval));
0698: case StreamTokenizer.TT_EOF:
0699: /* Comment out ResourcesMgr use in
0700: * initial CDC port.
0701: MessageFormat form = new MessageFormat(
0702: ResourcesMgr.getString
0703: ("expected [expect], read [end of file]"));
0704: */
0705: MessageFormat form = new MessageFormat(
0706: "expected [expect], read [end of file]");
0707: Object[] source = { expect };
0708: throw new ParsingException(form.format(source));
0709: case StreamTokenizer.TT_WORD:
0710: if (expect.equalsIgnoreCase(st.sval)) {
0711: lookahead = st.nextToken();
0712: } else if (expect.equalsIgnoreCase("permission type")) {
0713: value = st.sval;
0714: lookahead = st.nextToken();
0715: } else if (expect.equalsIgnoreCase("principal type")) {
0716: value = st.sval;
0717: lookahead = st.nextToken();
0718: } else {
0719: throw new ParsingException(st.lineno(), expect, st.sval);
0720: }
0721: break;
0722: case '"':
0723: if (expect.equalsIgnoreCase("quoted string")) {
0724: value = st.sval;
0725: lookahead = st.nextToken();
0726: } else if (expect.equalsIgnoreCase("permission type")) {
0727: value = st.sval;
0728: lookahead = st.nextToken();
0729: } else if (expect.equalsIgnoreCase("principal type")) {
0730: value = st.sval;
0731: lookahead = st.nextToken();
0732: } else {
0733: throw new ParsingException(st.lineno(), expect, st.sval);
0734: }
0735: break;
0736: case ',':
0737: if (expect.equalsIgnoreCase(","))
0738: lookahead = st.nextToken();
0739: else
0740: throw new ParsingException(st.lineno(), expect, ",");
0741: break;
0742: case '{':
0743: if (expect.equalsIgnoreCase("{"))
0744: lookahead = st.nextToken();
0745: else
0746: throw new ParsingException(st.lineno(), expect, "{");
0747: break;
0748: case '}':
0749: if (expect.equalsIgnoreCase("}"))
0750: lookahead = st.nextToken();
0751: else
0752: throw new ParsingException(st.lineno(), expect, "}");
0753: break;
0754: case ';':
0755: if (expect.equalsIgnoreCase(";"))
0756: lookahead = st.nextToken();
0757: else
0758: throw new ParsingException(st.lineno(), expect, ";");
0759: break;
0760: case '*':
0761: if (expect.equalsIgnoreCase("*"))
0762: lookahead = st.nextToken();
0763: else
0764: throw new ParsingException(st.lineno(), expect, "*");
0765: break;
0766: default:
0767: throw new ParsingException(st.lineno(), expect, new String(
0768: new char[] { (char) lookahead }));
0769: }
0770: return value;
0771: }
0772:
0773: /**
0774: * skip all tokens for this entry leaving the delimiter ";"
0775: * in the stream.
0776: */
0777: private void skipEntry() throws ParsingException, IOException {
0778: while (lookahead != ';') {
0779: switch (lookahead) {
0780: case StreamTokenizer.TT_NUMBER:
0781: /* Comment out ResourcesMgr use in
0782: * initial CDC port.
0783: throw new ParsingException(st.lineno(), ";",
0784: ResourcesMgr.getString("number ") +
0785: String.valueOf(st.nval));
0786: */
0787: throw new ParsingException(st.lineno(), ";", "number "
0788: + String.valueOf(st.nval));
0789: case StreamTokenizer.TT_EOF:
0790: /* Comment out ResourcesMgr use in
0791: * initial CDC port.
0792: throw new ParsingException(ResourcesMgr.getString
0793: ("expected [;], read [end of file]"));
0794: */
0795: throw new ParsingException(
0796: "expected [;], read [end of file]");
0797: default:
0798: lookahead = st.nextToken();
0799: }
0800: }
0801: }
0802:
0803: /**
0804: * Each grant entry in the policy configuration file is
0805: * represented by a
0806: * GrantEntry object. <p>
0807: *
0808: * <p>
0809: * For example, the entry
0810: * <pre>
0811: * grant signedBy "Duke" {
0812: * permission java.io.FilePermission "/tmp", "read,write";
0813: * };
0814: *
0815: * </pre>
0816: * is represented internally
0817: * <pre>
0818: *
0819: * pe = new PermissionEntry("java.io.FilePermission",
0820: * "/tmp", "read,write");
0821: *
0822: * ge = new GrantEntry("Duke", null);
0823: *
0824: * ge.add(pe);
0825: *
0826: * </pre>
0827: *
0828: * @author Roland Schemers
0829: *
0830: * version 1.19, 05/21/98
0831: */
0832:
0833: public static class GrantEntry {
0834:
0835: public String signedBy;
0836: public String codeBase;
0837: public LinkedList principals;
0838: public Vector permissionEntries;
0839:
0840: public GrantEntry() {
0841: principals = new LinkedList();
0842: permissionEntries = new Vector();
0843: }
0844:
0845: public GrantEntry(String signedBy, String codeBase) {
0846: this .codeBase = codeBase;
0847: this .signedBy = signedBy;
0848: principals = new LinkedList();
0849: permissionEntries = new Vector();
0850: }
0851:
0852: public void add(PermissionEntry pe) {
0853: permissionEntries.addElement(pe);
0854: }
0855:
0856: public boolean remove(PrincipalEntry pe) {
0857: return principals.remove(pe);
0858: }
0859:
0860: public boolean remove(PermissionEntry pe) {
0861: return permissionEntries.removeElement(pe);
0862: }
0863:
0864: public boolean contains(PrincipalEntry pe) {
0865: return principals.contains(pe);
0866: }
0867:
0868: public boolean contains(PermissionEntry pe) {
0869: return permissionEntries.contains(pe);
0870: }
0871:
0872: /**
0873: * Enumerate all the permission entries in this GrantEntry.
0874: */
0875: public Enumeration permissionElements() {
0876: return permissionEntries.elements();
0877: }
0878:
0879: public void write(PrintWriter out) {
0880: out.print("grant");
0881: if (signedBy != null) {
0882: out.print(" signedBy \"");
0883: out.print(signedBy);
0884: out.print('"');
0885: if (codeBase != null)
0886: out.print(", ");
0887: }
0888: if (codeBase != null) {
0889: out.print(" codeBase \"");
0890: out.print(codeBase);
0891: out.print('"');
0892: if (principals != null && principals.size() > 0)
0893: out.print(",\n");
0894: }
0895: if (principals != null && principals.size() > 0) {
0896: ListIterator pli = principals.listIterator();
0897: while (pli.hasNext()) {
0898: out.print(" ");
0899: PrincipalEntry pe = (PrincipalEntry) pli.next();
0900: pe.write(out);
0901: if (pli.hasNext())
0902: out.print(",\n");
0903: }
0904: }
0905: out.println(" {");
0906: Enumeration enum_ = permissionEntries.elements();
0907: while (enum_.hasMoreElements()) {
0908: PermissionEntry pe = (PermissionEntry) enum_
0909: .nextElement();
0910: out.write(" ");
0911: pe.write(out);
0912: }
0913: out.println("};");
0914: }
0915:
0916: public Object clone() {
0917: GrantEntry ge = new GrantEntry();
0918: ge.codeBase = this .codeBase;
0919: ge.signedBy = this .signedBy;
0920: ge.principals = new LinkedList(this .principals);
0921: ge.permissionEntries = new Vector(this .permissionEntries);
0922: return ge;
0923: }
0924: }
0925:
0926: /**
0927: * Principal info (class and name) in a grant entry
0928: */
0929: public static class PrincipalEntry {
0930:
0931: public static final String WILDCARD_CLASS = "WILDCARD_PRINCIPAL_CLASS";
0932: public static final String WILDCARD_NAME = "WILDCARD_PRINCIPAL_NAME";
0933:
0934: String principalClass;
0935: String principalName;
0936:
0937: /**
0938: * A PrincipalEntry consists of the <code>Principal</code>
0939: * class and <code>Principal</code> name.
0940: *
0941: * <p>
0942: *
0943: * @param principalClass the <code>Principal</code> class. <p>
0944: *
0945: * @param principalName the <code>Principal</code> name. <p>
0946: */
0947: public PrincipalEntry(String principalClass,
0948: String principalName) {
0949: if (principalClass == null || principalName == null)
0950: /* Comment out ResourcesMgr use in
0951: * initial CDC port.
0952: throw new NullPointerException(ResourcesMgr.getString(
0953: "null principalClass or principalName"));
0954: */
0955: throw new NullPointerException(
0956: "null principalClass or principalName");
0957: this .principalClass = principalClass;
0958: this .principalName = principalName;
0959: }
0960:
0961: public String getPrincipalClass() {
0962: return principalClass;
0963: }
0964:
0965: public String getPrincipalName() {
0966: return principalName;
0967: }
0968:
0969: public String getDisplayClass() {
0970: if (principalClass.equals(WILDCARD_CLASS)) {
0971: return "*";
0972: } else if (principalClass.equals(REPLACE_NAME)) {
0973: return "";
0974: } else
0975: return principalClass;
0976: }
0977:
0978: public String getDisplayName() {
0979: return getDisplayName(false);
0980: }
0981:
0982: public String getDisplayName(boolean addQuote) {
0983: if (principalName.equals(WILDCARD_NAME)) {
0984: return "*";
0985: } else {
0986: if (addQuote)
0987: return "\"" + principalName + "\"";
0988: else
0989: return principalName;
0990: }
0991: }
0992:
0993: public String toString() {
0994: if (!principalClass.equals(REPLACE_NAME)) {
0995: return getDisplayClass() + "/" + getDisplayName();
0996: } else {
0997: return getDisplayName();
0998: }
0999: }
1000:
1001: /**
1002: * Test for equality between the specified object and this object.
1003: * Two PrincipalEntries are equal if their PrincipalClass and
1004: * PrincipalName values are equal.
1005: *
1006: * <p>
1007: *
1008: * @param obj the object to test for equality with this object.
1009: *
1010: * @return true if the objects are equal, false otherwise.
1011: */
1012: public boolean equals(Object obj) {
1013: if (this == obj)
1014: return true;
1015:
1016: if (!(obj instanceof PrincipalEntry))
1017: return false;
1018:
1019: PrincipalEntry that = (PrincipalEntry) obj;
1020: if (this .principalClass.equals(that.principalClass)
1021: && this .principalName.equals(that.principalName)) {
1022: return true;
1023: }
1024:
1025: return false;
1026: }
1027:
1028: /**
1029: * Return a hashcode for this <code>PrincipalEntry</code>.
1030: *
1031: * <p>
1032: *
1033: * @return a hashcode for this <code>PrincipalEntry</code>.
1034: */
1035: public int hashCode() {
1036: return principalClass.hashCode();
1037: }
1038:
1039: public void write(PrintWriter out) {
1040: out.print("principal " + getDisplayClass() + " "
1041: + getDisplayName(true));
1042: }
1043: }
1044:
1045: /**
1046: * Each permission entry in the policy configuration file is
1047: * represented by a
1048: * PermissionEntry object. <p>
1049: *
1050: * <p>
1051: * For example, the entry
1052: * <pre>
1053: * permission java.io.FilePermission "/tmp", "read,write";
1054: * </pre>
1055: * is represented internally
1056: * <pre>
1057: *
1058: * pe = new PermissionEntry("java.io.FilePermission",
1059: * "/tmp", "read,write");
1060: * </pre>
1061: *
1062: * @author Roland Schemers
1063: *
1064: * version 1.19, 05/21/98
1065: */
1066:
1067: public static class PermissionEntry {
1068:
1069: public String permission;
1070: public String name;
1071: public String action;
1072: public String signedBy;
1073:
1074: public PermissionEntry() {
1075: }
1076:
1077: public PermissionEntry(String permission, String name,
1078: String action) {
1079: this .permission = permission;
1080: this .name = name;
1081: this .action = action;
1082: }
1083:
1084: /**
1085: * Calculates a hash code value for the object. Objects
1086: * which are equal will also have the same hashcode.
1087: */
1088: public int hashCode() {
1089: int retval = permission.hashCode();
1090: if (name != null)
1091: retval ^= name.hashCode();
1092: if (action != null)
1093: retval ^= action.hashCode();
1094: return retval;
1095: }
1096:
1097: public boolean equals(Object obj) {
1098: if (obj == this )
1099: return true;
1100:
1101: if (!(obj instanceof PermissionEntry))
1102: return false;
1103:
1104: PermissionEntry that = (PermissionEntry) obj;
1105:
1106: if (this .permission == null) {
1107: if (that.permission != null)
1108: return false;
1109: } else {
1110: if (!this .permission.equals(that.permission))
1111: return false;
1112: }
1113:
1114: if (this .name == null) {
1115: if (that.name != null)
1116: return false;
1117: } else {
1118: if (!this .name.equals(that.name))
1119: return false;
1120: }
1121:
1122: if (this .action == null) {
1123: if (that.action != null)
1124: return false;
1125: } else {
1126: if (!this .action.equals(that.action))
1127: return false;
1128: }
1129:
1130: if (this .signedBy == null) {
1131: if (that.signedBy != null)
1132: return false;
1133: } else {
1134: if (!this .signedBy.equals(that.signedBy))
1135: return false;
1136: }
1137:
1138: // everything matched -- the 2 objects are equal
1139: return true;
1140: }
1141:
1142: public void write(PrintWriter out) {
1143: out.print("permission ");
1144: out.print(permission);
1145: if (name != null) {
1146: out.print(" \"");
1147:
1148: // have to add escape chars for quotes
1149: if (name.indexOf("\"") != -1) {
1150: int numQuotes = 0;
1151: char[] chars = name.toCharArray();
1152:
1153: // count the number of quote chars
1154: for (int i = 0; i < chars.length; i++) {
1155: if (chars[i] == '"')
1156: numQuotes++;
1157: }
1158:
1159: // now, add an escape char before each quote
1160: char[] newChars = new char[chars.length + numQuotes];
1161: for (int i = 0, j = 0; i < chars.length; i++) {
1162: if (chars[i] != '"') {
1163: newChars[j++] = chars[i];
1164: } else {
1165: newChars[j++] = '\\';
1166: newChars[j++] = chars[i];
1167: }
1168: }
1169: name = new String(newChars);
1170: }
1171: out.print(name);
1172: out.print('"');
1173: }
1174: if (action != null) {
1175: out.print(", \"");
1176: out.print(action);
1177: out.print('"');
1178: }
1179: if (signedBy != null) {
1180: out.print(", signedBy \"");
1181: out.print(signedBy);
1182: out.print('"');
1183: }
1184: out.println(";");
1185: }
1186: }
1187:
1188: public static class ParsingException extends
1189: GeneralSecurityException {
1190:
1191: private String i18nMessage;
1192:
1193: /**
1194: * Constructs a ParsingException with the specified
1195: * detail message. A detail message is a String that describes
1196: * this particular exception, which may, for example, specify which
1197: * algorithm is not available.
1198: *
1199: * @param msg the detail message.
1200: */
1201: public ParsingException(String msg) {
1202: super (msg);
1203: i18nMessage = msg;
1204: }
1205:
1206: public ParsingException(int line, String msg) {
1207: super ("line " + line + ": " + msg);
1208: /* Comment out ResourcesMgr use in
1209: * initial CDC port.
1210: MessageFormat form = new MessageFormat
1211: (ResourcesMgr.getString("line number: msg"));
1212: */
1213: MessageFormat form = new MessageFormat("line number: msg");
1214: Object[] source = { new Integer(line), msg };
1215: i18nMessage = form.format(source);
1216: }
1217:
1218: public ParsingException(int line, String expect, String actual) {
1219: super ("line " + line + ": expected [" + expect
1220: + "], found [" + actual + "]");
1221: /* Comment out ResourcesMgr use in
1222: * initial CDC port.
1223: MessageFormat form = new MessageFormat(ResourcesMgr.getString
1224: ("line number: expected [expect], found [actual]"));
1225: */
1226: MessageFormat form = new MessageFormat(
1227: "line number: expected [expect], found [actual]");
1228: Object[] source = { new Integer(line), expect, actual };
1229: i18nMessage = form.format(source);
1230: }
1231:
1232: public String getLocalizedMessage() {
1233: return i18nMessage;
1234: }
1235: }
1236:
1237: public static void main(String arg[]) throws Exception {
1238: PolicyParser pp = new PolicyParser(true);
1239: pp.read(new FileReader(arg[0]));
1240: FileWriter fr = new FileWriter(arg[1]);
1241: pp.write(fr);
1242: fr.close();
1243: }
1244: }
|